001package net.minecraft.item;
002
003import cpw.mods.fml.relauncher.Side;
004import cpw.mods.fml.relauncher.SideOnly;
005import java.util.List;
006import net.minecraft.block.Block;
007import net.minecraft.block.material.MapColor;
008import net.minecraft.entity.Entity;
009import net.minecraft.entity.player.EntityPlayer;
010import net.minecraft.network.packet.Packet;
011import net.minecraft.network.packet.Packet131MapData;
012import net.minecraft.util.MathHelper;
013import net.minecraft.world.World;
014import net.minecraft.world.chunk.Chunk;
015import net.minecraft.world.storage.MapData;
016import net.minecraft.world.storage.MapInfo;
017
018public class ItemMap extends ItemMapBase
019{
020    protected ItemMap(int par1)
021    {
022        super(par1);
023        this.setHasSubtypes(true);
024    }
025
026    @SideOnly(Side.CLIENT)
027    public static MapData getMPMapData(short par0, World par1World)
028    {
029        String s = "map_" + par0;
030        MapData mapdata = (MapData)par1World.loadItemData(MapData.class, s);
031
032        if (mapdata == null)
033        {
034            mapdata = new MapData(s);
035            par1World.setItemData(s, mapdata);
036        }
037
038        return mapdata;
039    }
040
041    public MapData getMapData(ItemStack par1ItemStack, World par2World)
042    {
043        String s = "map_" + par1ItemStack.getItemDamage();
044        MapData mapdata = (MapData)par2World.loadItemData(MapData.class, s);
045
046        if (mapdata == null && !par2World.isRemote)
047        {
048            par1ItemStack.setItemDamage(par2World.getUniqueDataId("map"));
049            s = "map_" + par1ItemStack.getItemDamage();
050            mapdata = new MapData(s);
051            mapdata.scale = 3;
052            int i = 128 * (1 << mapdata.scale);
053            mapdata.xCenter = Math.round((float)par2World.getWorldInfo().getSpawnX() / (float)i) * i;
054            mapdata.zCenter = Math.round((float)(par2World.getWorldInfo().getSpawnZ() / i)) * i;
055            mapdata.dimension = par2World.provider.dimensionId;
056            mapdata.markDirty();
057            par2World.setItemData(s, mapdata);
058        }
059
060        return mapdata;
061    }
062
063    public void updateMapData(World par1World, Entity par2Entity, MapData par3MapData)
064    {
065        if (par1World.provider.dimensionId == par3MapData.dimension && par2Entity instanceof EntityPlayer)
066        {
067            short short1 = 128;
068            short short2 = 128;
069            int i = 1 << par3MapData.scale;
070            int j = par3MapData.xCenter;
071            int k = par3MapData.zCenter;
072            int l = MathHelper.floor_double(par2Entity.posX - (double)j) / i + short1 / 2;
073            int i1 = MathHelper.floor_double(par2Entity.posZ - (double)k) / i + short2 / 2;
074            int j1 = 128 / i;
075
076            if (par1World.provider.hasNoSky)
077            {
078                j1 /= 2;
079            }
080
081            MapInfo mapinfo = par3MapData.func_82568_a((EntityPlayer)par2Entity);
082            ++mapinfo.field_82569_d;
083
084            for (int k1 = l - j1 + 1; k1 < l + j1; ++k1)
085            {
086                if ((k1 & 15) == (mapinfo.field_82569_d & 15))
087                {
088                    int l1 = 255;
089                    int i2 = 0;
090                    double d0 = 0.0D;
091
092                    for (int j2 = i1 - j1 - 1; j2 < i1 + j1; ++j2)
093                    {
094                        if (k1 >= 0 && j2 >= -1 && k1 < short1 && j2 < short2)
095                        {
096                            int k2 = k1 - l;
097                            int l2 = j2 - i1;
098                            boolean flag = k2 * k2 + l2 * l2 > (j1 - 2) * (j1 - 2);
099                            int i3 = (j / i + k1 - short1 / 2) * i;
100                            int j3 = (k / i + j2 - short2 / 2) * i;
101                            int[] aint = new int[Block.blocksList.length];
102                            Chunk chunk = par1World.getChunkFromBlockCoords(i3, j3);
103
104                            if (!chunk.isEmpty())
105                            {
106                                int k3 = i3 & 15;
107                                int l3 = j3 & 15;
108                                int i4 = 0;
109                                double d1 = 0.0D;
110                                int j4;
111                                int k4;
112                                int l4;
113                                int i5;
114
115                                if (par1World.provider.hasNoSky)
116                                {
117                                    j4 = i3 + j3 * 231871;
118                                    j4 = j4 * j4 * 31287121 + j4 * 11;
119
120                                    if ((j4 >> 20 & 1) == 0)
121                                    {
122                                        aint[Block.dirt.blockID] += 10;
123                                    }
124                                    else
125                                    {
126                                        aint[Block.stone.blockID] += 10;
127                                    }
128
129                                    d1 = 100.0D;
130                                }
131                                else
132                                {
133                                    for (j4 = 0; j4 < i; ++j4)
134                                    {
135                                        for (k4 = 0; k4 < i; ++k4)
136                                        {
137                                            l4 = chunk.getHeightValue(j4 + k3, k4 + l3) + 1;
138                                            int j5 = 0;
139
140                                            if (l4 > 1)
141                                            {
142                                                boolean flag1;
143
144                                                do
145                                                {
146                                                    flag1 = true;
147                                                    j5 = chunk.getBlockID(j4 + k3, l4 - 1, k4 + l3);
148
149                                                    if (j5 == 0)
150                                                    {
151                                                        flag1 = false;
152                                                    }
153                                                    else if (l4 > 0 && j5 > 0 && Block.blocksList[j5].blockMaterial.materialMapColor == MapColor.airColor)
154                                                    {
155                                                        flag1 = false;
156                                                    }
157
158                                                    if (!flag1)
159                                                    {
160                                                        --l4;
161
162                                                        if (l4 <= 0)
163                                                        {
164                                                            break;
165                                                        }
166
167                                                        j5 = chunk.getBlockID(j4 + k3, l4 - 1, k4 + l3);
168                                                    }
169                                                }
170                                                while (l4 > 0 && !flag1);
171
172                                                if (l4 > 0 && j5 != 0 && Block.blocksList[j5].blockMaterial.isLiquid())
173                                                {
174                                                    i5 = l4 - 1;
175                                                    boolean flag2 = false;
176                                                    int k5;
177
178                                                    do
179                                                    {
180                                                        k5 = chunk.getBlockID(j4 + k3, i5--, k4 + l3);
181                                                        ++i4;
182                                                    }
183                                                    while (i5 > 0 && k5 != 0 && Block.blocksList[k5].blockMaterial.isLiquid());
184                                                }
185                                            }
186
187                                            d1 += (double)l4 / (double)(i * i);
188                                            ++aint[j5];
189                                        }
190                                    }
191                                }
192
193                                i4 /= i * i;
194                                j4 = 0;
195                                k4 = 0;
196
197                                for (l4 = 0; l4 < Block.blocksList.length; ++l4)
198                                {
199                                    if (aint[l4] > j4)
200                                    {
201                                        k4 = l4;
202                                        j4 = aint[l4];
203                                    }
204                                }
205
206                                double d2 = (d1 - d0) * 4.0D / (double)(i + 4) + ((double)(k1 + j2 & 1) - 0.5D) * 0.4D;
207                                byte b0 = 1;
208
209                                if (d2 > 0.6D)
210                                {
211                                    b0 = 2;
212                                }
213
214                                if (d2 < -0.6D)
215                                {
216                                    b0 = 0;
217                                }
218
219                                i5 = 0;
220
221                                if (k4 > 0)
222                                {
223                                    MapColor mapcolor = Block.blocksList[k4].blockMaterial.materialMapColor;
224
225                                    if (mapcolor == MapColor.waterColor)
226                                    {
227                                        d2 = (double)i4 * 0.1D + (double)(k1 + j2 & 1) * 0.2D;
228                                        b0 = 1;
229
230                                        if (d2 < 0.5D)
231                                        {
232                                            b0 = 2;
233                                        }
234
235                                        if (d2 > 0.9D)
236                                        {
237                                            b0 = 0;
238                                        }
239                                    }
240
241                                    i5 = mapcolor.colorIndex;
242                                }
243
244                                d0 = d1;
245
246                                if (j2 >= 0 && k2 * k2 + l2 * l2 < j1 * j1 && (!flag || (k1 + j2 & 1) != 0))
247                                {
248                                    byte b1 = par3MapData.colors[k1 + j2 * short1];
249                                    byte b2 = (byte)(i5 * 4 + b0);
250
251                                    if (b1 != b2)
252                                    {
253                                        if (l1 > j2)
254                                        {
255                                            l1 = j2;
256                                        }
257
258                                        if (i2 < j2)
259                                        {
260                                            i2 = j2;
261                                        }
262
263                                        par3MapData.colors[k1 + j2 * short1] = b2;
264                                    }
265                                }
266                            }
267                        }
268                    }
269
270                    if (l1 <= i2)
271                    {
272                        par3MapData.setColumnDirty(k1, l1, i2);
273                    }
274                }
275            }
276        }
277    }
278
279    /**
280     * Called each tick as long the item is on a player inventory. Uses by maps to check if is on a player hand and
281     * update it's contents.
282     */
283    public void onUpdate(ItemStack par1ItemStack, World par2World, Entity par3Entity, int par4, boolean par5)
284    {
285        if (!par2World.isRemote)
286        {
287            MapData mapdata = this.getMapData(par1ItemStack, par2World);
288
289            if (par3Entity instanceof EntityPlayer)
290            {
291                EntityPlayer entityplayer = (EntityPlayer)par3Entity;
292                mapdata.updateVisiblePlayers(entityplayer, par1ItemStack);
293            }
294
295            if (par5)
296            {
297                this.updateMapData(par2World, par3Entity, mapdata);
298            }
299        }
300    }
301
302    /**
303     * returns null if no update is to be sent
304     */
305    public Packet createMapDataPacket(ItemStack par1ItemStack, World par2World, EntityPlayer par3EntityPlayer)
306    {
307        byte[] abyte = this.getMapData(par1ItemStack, par2World).getUpdatePacketData(par1ItemStack, par2World, par3EntityPlayer);
308        return abyte == null ? null : new Packet131MapData((short)Item.map.itemID, (short)par1ItemStack.getItemDamage(), abyte);
309    }
310
311    /**
312     * Called when item is crafted/smelted. Used only by maps so far.
313     */
314    public void onCreated(ItemStack par1ItemStack, World par2World, EntityPlayer par3EntityPlayer)
315    {
316        if (par1ItemStack.hasTagCompound() && par1ItemStack.getTagCompound().getBoolean("map_is_scaling"))
317        {
318            MapData mapdata = Item.map.getMapData(par1ItemStack, par2World);
319            par1ItemStack.setItemDamage(par2World.getUniqueDataId("map"));
320            MapData mapdata1 = new MapData("map_" + par1ItemStack.getItemDamage());
321            mapdata1.scale = (byte)(mapdata.scale + 1);
322
323            if (mapdata1.scale > 4)
324            {
325                mapdata1.scale = 4;
326            }
327
328            mapdata1.xCenter = mapdata.xCenter;
329            mapdata1.zCenter = mapdata.zCenter;
330            mapdata1.dimension = mapdata.dimension;
331            mapdata1.markDirty();
332            par2World.setItemData("map_" + par1ItemStack.getItemDamage(), mapdata1);
333        }
334    }
335
336    @SideOnly(Side.CLIENT)
337
338    /**
339     * allows items to add custom lines of information to the mouseover description
340     */
341    public void addInformation(ItemStack par1ItemStack, EntityPlayer par2EntityPlayer, List par3List, boolean par4)
342    {
343        MapData mapdata = this.getMapData(par1ItemStack, par2EntityPlayer.worldObj);
344
345        if (par4)
346        {
347            if (mapdata == null)
348            {
349                par3List.add("Unknown map");
350            }
351            else
352            {
353                par3List.add("Scaling at 1:" + (1 << mapdata.scale));
354                par3List.add("(Level " + mapdata.scale + "/" + 4 + ")");
355            }
356        }
357    }
358}