001    package net.minecraftforge.common;
002    
003    import java.util.*;
004    import java.util.Map.Entry;
005    
006    import com.google.common.collect.ArrayListMultimap;
007    import com.google.common.collect.ListMultimap;
008    
009    import cpw.mods.fml.common.FMLLog;
010    import cpw.mods.fml.common.Loader;
011    
012    import net.minecraft.src.*;
013    import net.minecraftforge.event.ForgeEventFactory;
014    import net.minecraftforge.event.entity.item.ItemTossEvent;
015    import net.minecraftforge.event.entity.living.*;
016    import net.minecraftforge.event.entity.living.LivingEvent.*;
017    
018    public class ForgeHooks
019    {
020        static class GrassEntry extends WeightedRandomItem
021        {
022            public final Block block;
023            public final int metadata;
024            public GrassEntry(Block block, int meta, int weight)
025            {
026                super(weight);
027                this.block = block;
028                this.metadata = meta;
029            }
030        }
031    
032        static class SeedEntry extends WeightedRandomItem
033        {
034            public final ItemStack seed;
035            public SeedEntry(ItemStack seed, int weight)
036            {
037                super(weight);
038                this.seed = seed;
039            }
040        }
041        static final List<GrassEntry> grassList = new ArrayList<GrassEntry>();
042        static final List<SeedEntry> seedList = new ArrayList<SeedEntry>();
043    
044        public static void plantGrass(World world, int x, int y, int z)
045        {
046            GrassEntry grass = (GrassEntry)WeightedRandom.getRandomItem(world.rand, grassList);
047            if (grass == null || grass.block == null || !grass.block.canBlockStay(world, x, y, z))
048            {
049                return;
050            }
051            world.setBlockAndMetadataWithNotify(x, y, z, grass.block.blockID, grass.metadata);
052        }
053    
054        public static ItemStack getGrassSeed(World world)
055        {
056            SeedEntry entry = (SeedEntry)WeightedRandom.getRandomItem(world.rand, seedList);
057            if (entry == null || entry.seed == null)
058            {
059                return null;
060            }
061            return entry.seed.copy();
062        }
063    
064        private static boolean toolInit = false;
065        static HashMap<Item, List> toolClasses = new HashMap<Item, List>();
066        static HashMap<List, Integer> toolHarvestLevels = new HashMap<List, Integer>();
067        static HashSet<List> toolEffectiveness = new HashSet<List>();
068    
069        public static boolean canHarvestBlock(Block block, EntityPlayer player, int metadata)
070        {
071            if (block.blockMaterial.isHarvestable())
072            {
073                return true;
074            }
075    
076            ItemStack stack = player.inventory.getCurrentItem();
077            if (stack == null)
078            {
079                return player.canHarvestBlock(block);
080            }
081    
082            List info = (List)toolClasses.get(stack.getItem());
083            if (info == null)
084            {
085                return player.canHarvestBlock(block);
086            }
087    
088            Object[] tmp = info.toArray();
089            String toolClass = (String)tmp[0];
090            int harvestLevel = (Integer)tmp[1];
091    
092            Integer blockHarvestLevel = (Integer)toolHarvestLevels.get(Arrays.asList(block, metadata, toolClass));
093            if (blockHarvestLevel == null)
094            {
095                return player.canHarvestBlock(block);
096            }
097    
098            if (blockHarvestLevel > harvestLevel)
099            {
100                return false;
101            }
102            return true;
103        }
104    
105        public static float blockStrength(Block block, EntityPlayer player, World world, int x, int y, int z)
106        {
107            int metadata = world.getBlockMetadata(x, y, z);
108            float hardness = block.getBlockHardness(world, x, y, z);
109            if (hardness < 0.0F)
110            {
111                return 0.0F;
112            }
113    
114            if (!canHarvestBlock(block, player, metadata))
115            {
116                float speed = ForgeEventFactory.getBreakSpeed(player, block, metadata, 1.0f);
117                return (speed < 0 ? 0 : speed) / hardness / 100F;
118            }
119            else
120            {
121                 return player.getCurrentPlayerStrVsBlock(block, metadata) / hardness / 30F;
122            }
123        }
124    
125        public static boolean isToolEffective(ItemStack stack, Block block, int metadata)
126        {
127            List toolClass = (List)toolClasses.get(stack.getItem());
128            if (toolClass == null)
129            {
130                return false;
131            }
132            return toolEffectiveness.contains(Arrays.asList(block, metadata, (String)toolClass.get(0)));
133        }
134    
135        static void initTools()
136        {
137            if (toolInit)
138            {
139                return;
140            }
141            toolInit = true;
142    
143            MinecraftForge.setToolClass(Item.pickaxeWood,    "pickaxe", 0);
144            MinecraftForge.setToolClass(Item.pickaxeStone,   "pickaxe", 1);
145            MinecraftForge.setToolClass(Item.pickaxeSteel,   "pickaxe", 2);
146            MinecraftForge.setToolClass(Item.pickaxeGold,    "pickaxe", 0);
147            MinecraftForge.setToolClass(Item.pickaxeDiamond, "pickaxe", 3);
148    
149            MinecraftForge.setToolClass(Item.axeWood,    "axe", 0);
150            MinecraftForge.setToolClass(Item.axeStone,   "axe", 1);
151            MinecraftForge.setToolClass(Item.axeSteel,   "axe", 2);
152            MinecraftForge.setToolClass(Item.axeGold,    "axe", 0);
153            MinecraftForge.setToolClass(Item.axeDiamond, "axe", 3);
154    
155            MinecraftForge.setToolClass(Item.shovelWood,    "shovel", 0);
156            MinecraftForge.setToolClass(Item.shovelStone,   "shovel", 1);
157            MinecraftForge.setToolClass(Item.shovelSteel,   "shovel", 2);
158            MinecraftForge.setToolClass(Item.shovelGold,    "shovel", 0);
159            MinecraftForge.setToolClass(Item.shovelDiamond, "shovel", 3);
160    
161            for (Block block : ItemPickaxe.blocksEffectiveAgainst)
162            {
163                MinecraftForge.setBlockHarvestLevel(block, "pickaxe", 0);
164            }
165    
166            for (Block block : ItemSpade.blocksEffectiveAgainst)
167            {
168                MinecraftForge.setBlockHarvestLevel(block, "shovel", 0);
169            }
170    
171            for (Block block : ItemAxe.blocksEffectiveAgainst)
172            {
173                MinecraftForge.setBlockHarvestLevel(block, "axe", 0);
174            }
175    
176            MinecraftForge.setBlockHarvestLevel(Block.obsidian,     "pickaxe", 3);
177            MinecraftForge.setBlockHarvestLevel(Block.oreEmerald,   "pickaxe", 2);
178            MinecraftForge.setBlockHarvestLevel(Block.oreDiamond,   "pickaxe", 2);
179            MinecraftForge.setBlockHarvestLevel(Block.blockDiamond, "pickaxe", 2);
180            MinecraftForge.setBlockHarvestLevel(Block.oreGold,      "pickaxe", 2);
181            MinecraftForge.setBlockHarvestLevel(Block.blockGold,    "pickaxe", 2);
182            MinecraftForge.setBlockHarvestLevel(Block.oreIron,      "pickaxe", 1);
183            MinecraftForge.setBlockHarvestLevel(Block.blockSteel,   "pickaxe", 1);
184            MinecraftForge.setBlockHarvestLevel(Block.oreLapis,     "pickaxe", 1);
185            MinecraftForge.setBlockHarvestLevel(Block.blockLapis,   "pickaxe", 1);
186            MinecraftForge.setBlockHarvestLevel(Block.oreRedstone,  "pickaxe", 2);
187            MinecraftForge.setBlockHarvestLevel(Block.oreRedstoneGlowing, "pickaxe", 2);
188            MinecraftForge.removeBlockEffectiveness(Block.oreRedstone, "pickaxe");
189            MinecraftForge.removeBlockEffectiveness(Block.obsidian,    "pickaxe");
190            MinecraftForge.removeBlockEffectiveness(Block.oreRedstoneGlowing, "pickaxe");
191        }
192    
193        public static String getTexture(String _default, Object obj)
194        {
195            if (obj instanceof Item)
196            {
197                return ((Item)obj).getTextureFile();
198            }
199            else if (obj instanceof Block)
200            {
201                return ((Block)obj).getTextureFile();
202            }
203            else
204            {
205                return _default;
206            }
207        }
208    
209        public static int getTotalArmorValue(EntityPlayer player)
210        {
211            int ret = 0;
212            for (int x = 0; x < player.inventory.armorInventory.length; x++)
213            {
214                ItemStack stack = player.inventory.armorInventory[x];
215                if (stack != null && stack.getItem() instanceof ISpecialArmor)
216                {
217                    ret += ((ISpecialArmor)stack.getItem()).getArmorDisplay(player, stack, x);
218                }
219                else if (stack != null && stack.getItem() instanceof ItemArmor)
220                {
221                    ret += ((ItemArmor)stack.getItem()).damageReduceAmount;
222                }
223            }
224            return ret;
225        }
226    
227        static
228        {
229            grassList.add(new GrassEntry(Block.plantYellow, 0, 20));
230            grassList.add(new GrassEntry(Block.plantRed,    0, 10));
231            seedList.add(new SeedEntry(new ItemStack(Item.seeds), 10));
232            initTools();
233        }
234    
235        /**
236         * Called when a player uses 'pick block', calls new Entity and Block hooks.
237         */
238        public static boolean onPickBlock(MovingObjectPosition target, EntityPlayer player, World world)
239        {
240            ItemStack result = null;
241            boolean isCreative = player.capabilities.isCreativeMode;
242    
243            if (target.typeOfHit == EnumMovingObjectType.TILE)
244            {
245                int x = target.blockX;
246                int y = target.blockY;
247                int z = target.blockZ;
248                Block var8 = Block.blocksList[world.getBlockId(x, y, z)];
249    
250                if (var8 == null)
251                {
252                    return false;
253                }
254    
255                result = var8.getPickBlock(target, world, x, y, z);
256            }
257            else
258            {
259                if (target.typeOfHit != EnumMovingObjectType.ENTITY || target.entityHit == null || !isCreative)
260                {
261                    return false;
262                }
263    
264                result = target.entityHit.getPickedResult(target);
265            }
266    
267            if (result == null)
268            {
269                return false;
270            }
271    
272            for (int x = 0; x < 9; x++)
273            {
274                ItemStack stack = player.inventory.getStackInSlot(x);
275                if (stack != null && stack.isItemEqual(result))
276                {
277                    player.inventory.currentItem = x;
278                    return true;
279                }
280            }
281    
282            if (!isCreative)
283            {
284                return false;
285            }
286    
287            int slot = player.inventory.getFirstEmptyStack();
288            if (slot < 0 || slot >= 9)
289            {
290                slot = player.inventory.currentItem;
291            }
292    
293            player.inventory.setInventorySlotContents(slot, result);
294            player.inventory.currentItem = slot;
295            return true;
296        }
297    
298        //Optifine Helper Functions u.u, these are here specifically for Optifine
299        //Note: When using Optfine, these methods are invoked using reflection, which
300        //incurs a major performance penalty.
301        public static void onLivingSetAttackTarget(EntityLiving entity, EntityLiving target)
302        {
303            MinecraftForge.EVENT_BUS.post(new LivingSetAttackTargetEvent(entity, target));
304        }
305    
306        public static boolean onLivingUpdate(EntityLiving entity)
307        {
308            return MinecraftForge.EVENT_BUS.post(new LivingUpdateEvent(entity));
309        }
310    
311        public static boolean onLivingAttack(EntityLiving entity, DamageSource src, int amount)
312        {
313            return MinecraftForge.EVENT_BUS.post(new LivingAttackEvent(entity, src, amount));
314        }
315    
316        public static int onLivingHurt(EntityLiving entity, DamageSource src, int amount)
317        {
318            LivingHurtEvent event = new LivingHurtEvent(entity, src, amount);
319            return (MinecraftForge.EVENT_BUS.post(event) ? 0 : event.ammount);
320        }
321    
322        public static boolean onLivingDeath(EntityLiving entity, DamageSource src)
323        {
324            return MinecraftForge.EVENT_BUS.post(new LivingDeathEvent(entity, src));
325        }
326    
327        public static boolean onLivingDrops(EntityLiving entity, DamageSource source, ArrayList<EntityItem> drops, int lootingLevel, boolean recentlyHit, int specialDropValue)
328        {
329            return MinecraftForge.EVENT_BUS.post(new LivingDropsEvent(entity, source, drops, lootingLevel, recentlyHit, specialDropValue));
330        }
331    
332        public static float onLivingFall(EntityLiving entity, float distance)
333        {
334            LivingFallEvent event = new LivingFallEvent(entity, distance);
335            return (MinecraftForge.EVENT_BUS.post(event) ? 0.0f : event.distance);
336        }
337    
338        public static boolean isLivingOnLadder(Block block, World world, int x, int y, int z)
339        {
340            return block != null && block.isLadder(world, x, y, z);
341        }
342    
343        public static void onLivingJump(EntityLiving entity)
344        {
345            MinecraftForge.EVENT_BUS.post(new LivingJumpEvent(entity));
346        }
347    
348        public static EntityItem onPlayerTossEvent(EntityPlayer player, ItemStack item)
349        {
350            player.captureDrops = true;
351            EntityItem ret = player.dropPlayerItemWithRandomChoice(item, false);
352            player.capturedDrops.clear();
353            player.captureDrops = false;
354    
355            ItemTossEvent event = new ItemTossEvent(ret, player);
356            if (MinecraftForge.EVENT_BUS.post(event))
357            {
358                return null;
359            }
360    
361            player.joinEntityItemWithWorld(event.entityItem);
362            return event.entityItem;
363        }
364    }