001package net.minecraft.block;
002
003import java.util.Random;
004import net.minecraft.block.material.Material;
005import net.minecraft.world.IBlockAccess;
006import net.minecraft.world.World;
007
008public class BlockFlowing extends BlockFluid
009{
010    /**
011     * Number of horizontally adjacent liquid source blocks. Diagonal doesn't count. Only source blocks of the same
012     * liquid as the block using the field are counted.
013     */
014    int numAdjacentSources = 0;
015
016    /**
017     * Indicates whether the flow direction is optimal. Each array index corresponds to one of the four cardinal
018     * directions.
019     */
020    boolean[] isOptimalFlowDirection = new boolean[4];
021
022    /**
023     * The estimated cost to flow in a given direction from the current point. Each array index corresponds to one of
024     * the four cardinal directions.
025     */
026    int[] flowCost = new int[4];
027
028    protected BlockFlowing(int par1, Material par2Material)
029    {
030        super(par1, par2Material);
031    }
032
033    /**
034     * Updates the flow for the BlockFlowing object.
035     */
036    private void updateFlow(World par1World, int par2, int par3, int par4)
037    {
038        int var5 = par1World.getBlockMetadata(par2, par3, par4);
039        par1World.setBlockAndMetadata(par2, par3, par4, this.blockID + 1, var5);
040        par1World.markBlockRangeForRenderUpdate(par2, par3, par4, par2, par3, par4);
041    }
042
043    public boolean getBlocksMovement(IBlockAccess par1IBlockAccess, int par2, int par3, int par4)
044    {
045        return this.blockMaterial != Material.lava;
046    }
047
048    /**
049     * Ticks the block if it's been scheduled
050     */
051    public void updateTick(World par1World, int par2, int par3, int par4, Random par5Random)
052    {
053        int var6 = this.getFlowDecay(par1World, par2, par3, par4);
054        byte var7 = 1;
055
056        if (this.blockMaterial == Material.lava && !par1World.provider.isHellWorld)
057        {
058            var7 = 2;
059        }
060
061        boolean var8 = true;
062        int var10;
063
064        if (var6 > 0)
065        {
066            byte var9 = -100;
067            this.numAdjacentSources = 0;
068            int var12 = this.getSmallestFlowDecay(par1World, par2 - 1, par3, par4, var9);
069            var12 = this.getSmallestFlowDecay(par1World, par2 + 1, par3, par4, var12);
070            var12 = this.getSmallestFlowDecay(par1World, par2, par3, par4 - 1, var12);
071            var12 = this.getSmallestFlowDecay(par1World, par2, par3, par4 + 1, var12);
072            var10 = var12 + var7;
073
074            if (var10 >= 8 || var12 < 0)
075            {
076                var10 = -1;
077            }
078
079            if (this.getFlowDecay(par1World, par2, par3 + 1, par4) >= 0)
080            {
081                int var11 = this.getFlowDecay(par1World, par2, par3 + 1, par4);
082
083                if (var11 >= 8)
084                {
085                    var10 = var11;
086                }
087                else
088                {
089                    var10 = var11 + 8;
090                }
091            }
092
093            if (this.numAdjacentSources >= 2 && this.blockMaterial == Material.water)
094            {
095                if (par1World.getBlockMaterial(par2, par3 - 1, par4).isSolid())
096                {
097                    var10 = 0;
098                }
099                else if (par1World.getBlockMaterial(par2, par3 - 1, par4) == this.blockMaterial && par1World.getBlockMetadata(par2, par3, par4) == 0)
100                {
101                    var10 = 0;
102                }
103            }
104
105            if (this.blockMaterial == Material.lava && var6 < 8 && var10 < 8 && var10 > var6 && par5Random.nextInt(4) != 0)
106            {
107                var10 = var6;
108                var8 = false;
109            }
110
111            if (var10 == var6)
112            {
113                if (var8)
114                {
115                    this.updateFlow(par1World, par2, par3, par4);
116                }
117            }
118            else
119            {
120                var6 = var10;
121
122                if (var10 < 0)
123                {
124                    par1World.setBlockWithNotify(par2, par3, par4, 0);
125                }
126                else
127                {
128                    par1World.setBlockMetadataWithNotify(par2, par3, par4, var10);
129                    par1World.scheduleBlockUpdate(par2, par3, par4, this.blockID, this.tickRate());
130                    par1World.notifyBlocksOfNeighborChange(par2, par3, par4, this.blockID);
131                }
132            }
133        }
134        else
135        {
136            this.updateFlow(par1World, par2, par3, par4);
137        }
138
139        if (this.liquidCanDisplaceBlock(par1World, par2, par3 - 1, par4))
140        {
141            if (this.blockMaterial == Material.lava && par1World.getBlockMaterial(par2, par3 - 1, par4) == Material.water)
142            {
143                par1World.setBlockWithNotify(par2, par3 - 1, par4, Block.stone.blockID);
144                this.triggerLavaMixEffects(par1World, par2, par3 - 1, par4);
145                return;
146            }
147
148            if (var6 >= 8)
149            {
150                this.flowIntoBlock(par1World, par2, par3 - 1, par4, var6);
151            }
152            else
153            {
154                this.flowIntoBlock(par1World, par2, par3 - 1, par4, var6 + 8);
155            }
156        }
157        else if (var6 >= 0 && (var6 == 0 || this.blockBlocksFlow(par1World, par2, par3 - 1, par4)))
158        {
159            boolean[] var13 = this.getOptimalFlowDirections(par1World, par2, par3, par4);
160            var10 = var6 + var7;
161
162            if (var6 >= 8)
163            {
164                var10 = 1;
165            }
166
167            if (var10 >= 8)
168            {
169                return;
170            }
171
172            if (var13[0])
173            {
174                this.flowIntoBlock(par1World, par2 - 1, par3, par4, var10);
175            }
176
177            if (var13[1])
178            {
179                this.flowIntoBlock(par1World, par2 + 1, par3, par4, var10);
180            }
181
182            if (var13[2])
183            {
184                this.flowIntoBlock(par1World, par2, par3, par4 - 1, var10);
185            }
186
187            if (var13[3])
188            {
189                this.flowIntoBlock(par1World, par2, par3, par4 + 1, var10);
190            }
191        }
192    }
193
194    /**
195     * flowIntoBlock(World world, int x, int y, int z, int newFlowDecay) - Flows into the block at the coordinates and
196     * changes the block type to the liquid.
197     */
198    private void flowIntoBlock(World par1World, int par2, int par3, int par4, int par5)
199    {
200        if (this.liquidCanDisplaceBlock(par1World, par2, par3, par4))
201        {
202            int var6 = par1World.getBlockId(par2, par3, par4);
203
204            if (var6 > 0)
205            {
206                if (this.blockMaterial == Material.lava)
207                {
208                    this.triggerLavaMixEffects(par1World, par2, par3, par4);
209                }
210                else
211                {
212                    Block.blocksList[var6].dropBlockAsItem(par1World, par2, par3, par4, par1World.getBlockMetadata(par2, par3, par4), 0);
213                }
214            }
215
216            par1World.setBlockAndMetadataWithNotify(par2, par3, par4, this.blockID, par5);
217        }
218    }
219
220    /**
221     * calculateFlowCost(World world, int x, int y, int z, int accumulatedCost, int previousDirectionOfFlow) - Used to
222     * determine the path of least resistance, this method returns the lowest possible flow cost for the direction of
223     * flow indicated. Each necessary horizontal flow adds to the flow cost.
224     */
225    private int calculateFlowCost(World par1World, int par2, int par3, int par4, int par5, int par6)
226    {
227        int var7 = 1000;
228
229        for (int var8 = 0; var8 < 4; ++var8)
230        {
231            if ((var8 != 0 || par6 != 1) && (var8 != 1 || par6 != 0) && (var8 != 2 || par6 != 3) && (var8 != 3 || par6 != 2))
232            {
233                int var9 = par2;
234                int var11 = par4;
235
236                if (var8 == 0)
237                {
238                    var9 = par2 - 1;
239                }
240
241                if (var8 == 1)
242                {
243                    ++var9;
244                }
245
246                if (var8 == 2)
247                {
248                    var11 = par4 - 1;
249                }
250
251                if (var8 == 3)
252                {
253                    ++var11;
254                }
255
256                if (!this.blockBlocksFlow(par1World, var9, par3, var11) && (par1World.getBlockMaterial(var9, par3, var11) != this.blockMaterial || par1World.getBlockMetadata(var9, par3, var11) != 0))
257                {
258                    if (!this.blockBlocksFlow(par1World, var9, par3 - 1, var11))
259                    {
260                        return par5;
261                    }
262
263                    if (par5 < 4)
264                    {
265                        int var12 = this.calculateFlowCost(par1World, var9, par3, var11, par5 + 1, var8);
266
267                        if (var12 < var7)
268                        {
269                            var7 = var12;
270                        }
271                    }
272                }
273            }
274        }
275
276        return var7;
277    }
278
279    /**
280     * Returns a boolean array indicating which flow directions are optimal based on each direction's calculated flow
281     * cost. Each array index corresponds to one of the four cardinal directions. A value of true indicates the
282     * direction is optimal.
283     */
284    private boolean[] getOptimalFlowDirections(World par1World, int par2, int par3, int par4)
285    {
286        int var5;
287        int var6;
288
289        for (var5 = 0; var5 < 4; ++var5)
290        {
291            this.flowCost[var5] = 1000;
292            var6 = par2;
293            int var8 = par4;
294
295            if (var5 == 0)
296            {
297                var6 = par2 - 1;
298            }
299
300            if (var5 == 1)
301            {
302                ++var6;
303            }
304
305            if (var5 == 2)
306            {
307                var8 = par4 - 1;
308            }
309
310            if (var5 == 3)
311            {
312                ++var8;
313            }
314
315            if (!this.blockBlocksFlow(par1World, var6, par3, var8) && (par1World.getBlockMaterial(var6, par3, var8) != this.blockMaterial || par1World.getBlockMetadata(var6, par3, var8) != 0))
316            {
317                if (this.blockBlocksFlow(par1World, var6, par3 - 1, var8))
318                {
319                    this.flowCost[var5] = this.calculateFlowCost(par1World, var6, par3, var8, 1, var5);
320                }
321                else
322                {
323                    this.flowCost[var5] = 0;
324                }
325            }
326        }
327
328        var5 = this.flowCost[0];
329
330        for (var6 = 1; var6 < 4; ++var6)
331        {
332            if (this.flowCost[var6] < var5)
333            {
334                var5 = this.flowCost[var6];
335            }
336        }
337
338        for (var6 = 0; var6 < 4; ++var6)
339        {
340            this.isOptimalFlowDirection[var6] = this.flowCost[var6] == var5;
341        }
342
343        return this.isOptimalFlowDirection;
344    }
345
346    /**
347     * Returns true if block at coords blocks fluids
348     */
349    private boolean blockBlocksFlow(World par1World, int par2, int par3, int par4)
350    {
351        int var5 = par1World.getBlockId(par2, par3, par4);
352
353        if (var5 != Block.doorWood.blockID && var5 != Block.doorSteel.blockID && var5 != Block.signPost.blockID && var5 != Block.ladder.blockID && var5 != Block.reed.blockID)
354        {
355            if (var5 == 0)
356            {
357                return false;
358            }
359            else
360            {
361                Material var6 = Block.blocksList[var5].blockMaterial;
362                return var6 == Material.portal ? true : var6.blocksMovement();
363            }
364        }
365        else
366        {
367            return true;
368        }
369    }
370
371    /**
372     * getSmallestFlowDecay(World world, intx, int y, int z, int currentSmallestFlowDecay) - Looks up the flow decay at
373     * the coordinates given and returns the smaller of this value or the provided currentSmallestFlowDecay. If one
374     * value is valid and the other isn't, the valid value will be returned. Valid values are >= 0. Flow decay is the
375     * amount that a liquid has dissipated. 0 indicates a source block.
376     */
377    protected int getSmallestFlowDecay(World par1World, int par2, int par3, int par4, int par5)
378    {
379        int var6 = this.getFlowDecay(par1World, par2, par3, par4);
380
381        if (var6 < 0)
382        {
383            return par5;
384        }
385        else
386        {
387            if (var6 == 0)
388            {
389                ++this.numAdjacentSources;
390            }
391
392            if (var6 >= 8)
393            {
394                var6 = 0;
395            }
396
397            return par5 >= 0 && var6 >= par5 ? par5 : var6;
398        }
399    }
400
401    /**
402     * Returns true if the block at the coordinates can be displaced by the liquid.
403     */
404    private boolean liquidCanDisplaceBlock(World par1World, int par2, int par3, int par4)
405    {
406        Material var5 = par1World.getBlockMaterial(par2, par3, par4);
407        return var5 == this.blockMaterial ? false : (var5 == Material.lava ? false : !this.blockBlocksFlow(par1World, par2, par3, par4));
408    }
409
410    /**
411     * Called whenever the block is added into the world. Args: world, x, y, z
412     */
413    public void onBlockAdded(World par1World, int par2, int par3, int par4)
414    {
415        super.onBlockAdded(par1World, par2, par3, par4);
416
417        if (par1World.getBlockId(par2, par3, par4) == this.blockID)
418        {
419            par1World.scheduleBlockUpdate(par2, par3, par4, this.blockID, this.tickRate());
420        }
421    }
422
423    public boolean func_82506_l()
424    {
425        return false;
426    }
427}