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.entity.Entity;
008import net.minecraft.item.ItemMonsterPlacer;
009import net.minecraft.util.AxisAlignedBB;
010import net.minecraft.world.IBlockAccess;
011import net.minecraft.world.World;
012
013public class BlockPortal extends BlockBreakable
014{
015    public BlockPortal(int par1)
016    {
017        super(par1, "portal", Material.portal, false);
018        this.setTickRandomly(true);
019    }
020
021    /**
022     * Ticks the block if it's been scheduled
023     */
024    public void updateTick(World par1World, int par2, int par3, int par4, Random par5Random)
025    {
026        super.updateTick(par1World, par2, par3, par4, par5Random);
027
028        if (par1World.provider.isSurfaceWorld() && par5Random.nextInt(2000) < par1World.difficultySetting)
029        {
030            int l;
031
032            for (l = par3; !par1World.doesBlockHaveSolidTopSurface(par2, l, par4) && l > 0; --l)
033            {
034                ;
035            }
036
037            if (l > 0 && !par1World.isBlockNormalCube(par2, l + 1, par4))
038            {
039                Entity entity = ItemMonsterPlacer.spawnCreature(par1World, 57, (double)par2 + 0.5D, (double)l + 1.1D, (double)par4 + 0.5D);
040
041                if (entity != null)
042                {
043                    entity.timeUntilPortal = entity.getPortalCooldown();
044                }
045            }
046        }
047    }
048
049    /**
050     * Returns a bounding box from the pool of bounding boxes (this means this box can change after the pool has been
051     * cleared to be reused)
052     */
053    public AxisAlignedBB getCollisionBoundingBoxFromPool(World par1World, int par2, int par3, int par4)
054    {
055        return null;
056    }
057
058    /**
059     * Updates the blocks bounds based on its current state. Args: world, x, y, z
060     */
061    public void setBlockBoundsBasedOnState(IBlockAccess par1IBlockAccess, int par2, int par3, int par4)
062    {
063        float f;
064        float f1;
065
066        if (par1IBlockAccess.getBlockId(par2 - 1, par3, par4) != this.blockID && par1IBlockAccess.getBlockId(par2 + 1, par3, par4) != this.blockID)
067        {
068            f = 0.125F;
069            f1 = 0.5F;
070            this.setBlockBounds(0.5F - f, 0.0F, 0.5F - f1, 0.5F + f, 1.0F, 0.5F + f1);
071        }
072        else
073        {
074            f = 0.5F;
075            f1 = 0.125F;
076            this.setBlockBounds(0.5F - f, 0.0F, 0.5F - f1, 0.5F + f, 1.0F, 0.5F + f1);
077        }
078    }
079
080    /**
081     * Is this block (a) opaque and (b) a full 1m cube?  This determines whether or not to render the shared face of two
082     * adjacent blocks and also whether the player can attach torches, redstone wire, etc to this block.
083     */
084    public boolean isOpaqueCube()
085    {
086        return false;
087    }
088
089    /**
090     * If this block doesn't render as an ordinary block it will return False (examples: signs, buttons, stairs, etc)
091     */
092    public boolean renderAsNormalBlock()
093    {
094        return false;
095    }
096
097    /**
098     * Checks to see if this location is valid to create a portal and will return True if it does. Args: world, x, y, z
099     */
100    public boolean tryToCreatePortal(World par1World, int par2, int par3, int par4)
101    {
102        byte b0 = 0;
103        byte b1 = 0;
104
105        if (par1World.getBlockId(par2 - 1, par3, par4) == Block.obsidian.blockID || par1World.getBlockId(par2 + 1, par3, par4) == Block.obsidian.blockID)
106        {
107            b0 = 1;
108        }
109
110        if (par1World.getBlockId(par2, par3, par4 - 1) == Block.obsidian.blockID || par1World.getBlockId(par2, par3, par4 + 1) == Block.obsidian.blockID)
111        {
112            b1 = 1;
113        }
114
115        if (b0 == b1)
116        {
117            return false;
118        }
119        else
120        {
121            if (par1World.getBlockId(par2 - b0, par3, par4 - b1) == 0)
122            {
123                par2 -= b0;
124                par4 -= b1;
125            }
126
127            int l;
128            int i1;
129
130            for (l = -1; l <= 2; ++l)
131            {
132                for (i1 = -1; i1 <= 3; ++i1)
133                {
134                    boolean flag = l == -1 || l == 2 || i1 == -1 || i1 == 3;
135
136                    if (l != -1 && l != 2 || i1 != -1 && i1 != 3)
137                    {
138                        int j1 = par1World.getBlockId(par2 + b0 * l, par3 + i1, par4 + b1 * l);
139
140                        if (flag)
141                        {
142                            if (j1 != Block.obsidian.blockID)
143                            {
144                                return false;
145                            }
146                        }
147                        else if (j1 != 0 && j1 != Block.fire.blockID)
148                        {
149                            return false;
150                        }
151                    }
152                }
153            }
154
155            for (l = 0; l < 2; ++l)
156            {
157                for (i1 = 0; i1 < 3; ++i1)
158                {
159                    par1World.setBlockAndMetadataWithNotify(par2 + b0 * l, par3 + i1, par4 + b1 * l, Block.portal.blockID, 0, 2);
160                }
161            }
162
163            return true;
164        }
165    }
166
167    /**
168     * Lets the block know when one of its neighbor changes. Doesn't know which neighbor changed (coordinates passed are
169     * their own) Args: x, y, z, neighbor blockID
170     */
171    public void onNeighborBlockChange(World par1World, int par2, int par3, int par4, int par5)
172    {
173        byte b0 = 0;
174        byte b1 = 1;
175
176        if (par1World.getBlockId(par2 - 1, par3, par4) == this.blockID || par1World.getBlockId(par2 + 1, par3, par4) == this.blockID)
177        {
178            b0 = 1;
179            b1 = 0;
180        }
181
182        int i1;
183
184        for (i1 = par3; par1World.getBlockId(par2, i1 - 1, par4) == this.blockID; --i1)
185        {
186            ;
187        }
188
189        if (par1World.getBlockId(par2, i1 - 1, par4) != Block.obsidian.blockID)
190        {
191            par1World.func_94571_i(par2, par3, par4);
192        }
193        else
194        {
195            int j1;
196
197            for (j1 = 1; j1 < 4 && par1World.getBlockId(par2, i1 + j1, par4) == this.blockID; ++j1)
198            {
199                ;
200            }
201
202            if (j1 == 3 && par1World.getBlockId(par2, i1 + j1, par4) == Block.obsidian.blockID)
203            {
204                boolean flag = par1World.getBlockId(par2 - 1, par3, par4) == this.blockID || par1World.getBlockId(par2 + 1, par3, par4) == this.blockID;
205                boolean flag1 = par1World.getBlockId(par2, par3, par4 - 1) == this.blockID || par1World.getBlockId(par2, par3, par4 + 1) == this.blockID;
206
207                if (flag && flag1)
208                {
209                    par1World.func_94571_i(par2, par3, par4);
210                }
211                else
212                {
213                    if ((par1World.getBlockId(par2 + b0, par3, par4 + b1) != Block.obsidian.blockID || par1World.getBlockId(par2 - b0, par3, par4 - b1) != this.blockID) && (par1World.getBlockId(par2 - b0, par3, par4 - b1) != Block.obsidian.blockID || par1World.getBlockId(par2 + b0, par3, par4 + b1) != this.blockID))
214                    {
215                        par1World.func_94571_i(par2, par3, par4);
216                    }
217                }
218            }
219            else
220            {
221                par1World.func_94571_i(par2, par3, par4);
222            }
223        }
224    }
225
226    @SideOnly(Side.CLIENT)
227
228    /**
229     * Returns true if the given side of this block type should be rendered, if the adjacent block is at the given
230     * coordinates.  Args: blockAccess, x, y, z, side
231     */
232    public boolean shouldSideBeRendered(IBlockAccess par1IBlockAccess, int par2, int par3, int par4, int par5)
233    {
234        if (par1IBlockAccess.getBlockId(par2, par3, par4) == this.blockID)
235        {
236            return false;
237        }
238        else
239        {
240            boolean flag = par1IBlockAccess.getBlockId(par2 - 1, par3, par4) == this.blockID && par1IBlockAccess.getBlockId(par2 - 2, par3, par4) != this.blockID;
241            boolean flag1 = par1IBlockAccess.getBlockId(par2 + 1, par3, par4) == this.blockID && par1IBlockAccess.getBlockId(par2 + 2, par3, par4) != this.blockID;
242            boolean flag2 = par1IBlockAccess.getBlockId(par2, par3, par4 - 1) == this.blockID && par1IBlockAccess.getBlockId(par2, par3, par4 - 2) != this.blockID;
243            boolean flag3 = par1IBlockAccess.getBlockId(par2, par3, par4 + 1) == this.blockID && par1IBlockAccess.getBlockId(par2, par3, par4 + 2) != this.blockID;
244            boolean flag4 = flag || flag1;
245            boolean flag5 = flag2 || flag3;
246            return flag4 && par5 == 4 ? true : (flag4 && par5 == 5 ? true : (flag5 && par5 == 2 ? true : flag5 && par5 == 3));
247        }
248    }
249
250    /**
251     * Returns the quantity of items to drop on block destruction.
252     */
253    public int quantityDropped(Random par1Random)
254    {
255        return 0;
256    }
257
258    /**
259     * Triggered whenever an entity collides with this block (enters into the block). Args: world, x, y, z, entity
260     */
261    public void onEntityCollidedWithBlock(World par1World, int par2, int par3, int par4, Entity par5Entity)
262    {
263        if (par5Entity.ridingEntity == null && par5Entity.riddenByEntity == null)
264        {
265            par5Entity.setInPortal();
266        }
267    }
268
269    @SideOnly(Side.CLIENT)
270
271    /**
272     * Returns which pass should this block be rendered on. 0 for solids and 1 for alpha
273     */
274    public int getRenderBlockPass()
275    {
276        return 1;
277    }
278
279    @SideOnly(Side.CLIENT)
280
281    /**
282     * A randomly called display update to be able to add particles or other items for display
283     */
284    public void randomDisplayTick(World par1World, int par2, int par3, int par4, Random par5Random)
285    {
286        if (par5Random.nextInt(100) == 0)
287        {
288            par1World.playSound((double)par2 + 0.5D, (double)par3 + 0.5D, (double)par4 + 0.5D, "portal.portal", 0.5F, par5Random.nextFloat() * 0.4F + 0.8F, false);
289        }
290
291        for (int l = 0; l < 4; ++l)
292        {
293            double d0 = (double)((float)par2 + par5Random.nextFloat());
294            double d1 = (double)((float)par3 + par5Random.nextFloat());
295            double d2 = (double)((float)par4 + par5Random.nextFloat());
296            double d3 = 0.0D;
297            double d4 = 0.0D;
298            double d5 = 0.0D;
299            int i1 = par5Random.nextInt(2) * 2 - 1;
300            d3 = ((double)par5Random.nextFloat() - 0.5D) * 0.5D;
301            d4 = ((double)par5Random.nextFloat() - 0.5D) * 0.5D;
302            d5 = ((double)par5Random.nextFloat() - 0.5D) * 0.5D;
303
304            if (par1World.getBlockId(par2 - 1, par3, par4) != this.blockID && par1World.getBlockId(par2 + 1, par3, par4) != this.blockID)
305            {
306                d0 = (double)par2 + 0.5D + 0.25D * (double)i1;
307                d3 = (double)(par5Random.nextFloat() * 2.0F * (float)i1);
308            }
309            else
310            {
311                d2 = (double)par4 + 0.5D + 0.25D * (double)i1;
312                d5 = (double)(par5Random.nextFloat() * 2.0F * (float)i1);
313            }
314
315            par1World.spawnParticle("portal", d0, d1, d2, d3, d4, d5);
316        }
317    }
318
319    @SideOnly(Side.CLIENT)
320
321    /**
322     * only called by clickMiddleMouseButton , and passed to inventory.setCurrentItem (along with isCreative)
323     */
324    public int idPicked(World par1World, int par2, int par3, int par4)
325    {
326        return 0;
327    }
328}