package openblocks.common; import com.google.common.base.Strings; import com.google.common.base.Supplier; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Maps; import cpw.mods.fml.common.eventhandler.SubscribeEvent; import java.util.Map; import java.util.Random; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityList; import net.minecraft.entity.EntityLiving; import net.minecraft.entity.item.EntityItem; import net.minecraft.entity.passive.EntityOcelot; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.init.Items; import net.minecraft.item.ItemStack; import net.minecraft.world.World; import net.minecraftforge.event.entity.living.LivingDropsEvent; import openblocks.Config; import openblocks.OpenBlocks; import openblocks.common.item.ItemTrophyBlock; import openblocks.common.tileentity.TileEntityTrophy; import openblocks.trophy.BlazeBehavior; import openblocks.trophy.CaveSpiderBehavior; import openblocks.trophy.CreeperBehavior; import openblocks.trophy.EndermanBehavior; import openblocks.trophy.ITrophyBehavior; import openblocks.trophy.ItemDropBehavior; import openblocks.trophy.MooshroomBehavior; import openblocks.trophy.SkeletonBehavior; import openblocks.trophy.SnowmanBehavior; import openblocks.trophy.SquidBehavior; import openblocks.trophy.WitchBehavior; import openmods.Log; import openmods.calc.Environment; import openmods.calc.ExprType; import openmods.calc.SingleExprEvaluator; import openmods.calc.SingleExprEvaluator.EnvironmentConfigurator; import openmods.calc.types.fp.DoubleCalculatorFactory; import openmods.config.properties.ConfigurationChange; import openmods.reflection.ReflectionHelper; public class TrophyHandler { private static final Map<Trophy, Entity> ENTITY_CACHE = Maps.newHashMap(); private final Random fallbackDropChance = new Random(); private final SingleExprEvaluator<Double, ExprType> dropChangeCalculator = SingleExprEvaluator.create(DoubleCalculatorFactory.createDefault()); { updateDropChanceFormula(); } @SubscribeEvent public void onConfigChange(ConfigurationChange.Post evt) { if (evt.check("trophy", "trophyDropChanceFormula")) updateDropChanceFormula(); } private void updateDropChanceFormula() { dropChangeCalculator.setExpr(ExprType.INFIX, Config.trophyDropChanceFormula); } public static Entity getEntityFromCache(Trophy trophy) { Entity entity = ENTITY_CACHE.get(trophy); if (entity == null) { if (!ENTITY_CACHE.containsKey(trophy)) { try { entity = trophy.createEntity(); } catch (Throwable t) { Log.severe(t, "Failed to create dummy entity for trophy %s", trophy); } } ENTITY_CACHE.put(trophy, entity); } return entity; } private static Entity setSlimeSize(Entity entity, int size) { try { ReflectionHelper.call(entity, new String[] { "func_70799_a", "setSlimeSize" }, ReflectionHelper.primitive(size)); } catch (Exception e) { Log.warn(e, "Can't update slime size"); } return entity; } public enum Trophy { Wolf(), Chicken(new ItemDropBehavior(10000, new ItemStack(Items.egg), "mob.chicken.plop")), Cow(new ItemDropBehavior(20000, new ItemStack(Items.leather))), Creeper(new CreeperBehavior()), Skeleton(new SkeletonBehavior()), PigZombie(new ItemDropBehavior(20000, new ItemStack(Items.gold_nugget))), Bat(1.0, -0.3), Zombie(), Witch(0.35, new WitchBehavior()), Villager(), Ozelot() { @Override protected Entity createEntity() { Entity entity = super.createEntity(); try { ((EntityOcelot)entity).setTamed(true); } catch (ClassCastException e) { Log.warn("Invalid cat entity class: %s", entity.getClass()); } return entity; } }, Sheep(), Blaze(new BlazeBehavior()), Silverfish(), Spider(), CaveSpider(new CaveSpiderBehavior()), Slime(0.6) { @Override protected Entity createEntity() { return setSlimeSize(super.createEntity(), 1); } }, Ghast(0.1, 0.3), Enderman(0.3, new EndermanBehavior()), LavaSlime(0.6) { @Override protected Entity createEntity() { return setSlimeSize(super.createEntity(), 1); } }, Squid(0.3, 0.5, new SquidBehavior()), MushroomCow(new MooshroomBehavior()), VillagerGolem(0.3), SnowMan(new SnowmanBehavior()), Pig(new ItemDropBehavior(20000, new ItemStack(Items.porkchop))); private double scale = 0.4; private double verticalOffset = 0.0; private ITrophyBehavior behavior; Trophy() {} Trophy(ITrophyBehavior behavior) { this.behavior = behavior; } Trophy(double scale) { this.scale = scale; } Trophy(double scale, ITrophyBehavior behavior) { this.scale = scale; this.behavior = behavior; } Trophy(double scale, double verticalOffset) { this(scale); this.verticalOffset = verticalOffset; } Trophy(double scale, double verticalOffset, ITrophyBehavior behavior) { this(scale, verticalOffset); this.behavior = behavior; } public double getVerticalOffset() { return verticalOffset; } public double getScale() { return scale; } public Entity getEntity() { return getEntityFromCache(this); } public ItemStack getItemStack() { return ItemTrophyBlock.putMetadata(new ItemStack(OpenBlocks.Blocks.trophy), this); } public void playSound(World world, double x, double y, double z) { if (world == null) return; Entity e = getEntity(); if (e instanceof EntityLiving) { e.posX = x; e.posY = y; e.posZ = z; synchronized (e) { e.worldObj = world; ((EntityLiving)e).playLivingSound(); e.worldObj = null; } } } public int executeActivateBehavior(TileEntityTrophy tile, EntityPlayer player) { if (behavior != null) return behavior.executeActivateBehavior(tile, player); return 0; } public void executeTickBehavior(TileEntityTrophy tile) { if (behavior != null) behavior.executeTickBehavior(tile); } protected Entity createEntity() { return EntityList.createEntityByName(toString(), null); } static { ImmutableMap.Builder<String, Trophy> builder = ImmutableMap.builder(); for (Trophy t : values()) builder.put(t.name(), t); TYPES = builder.build(); } public final static Map<String, Trophy> TYPES; public final static Trophy[] VALUES = values(); } @SubscribeEvent public void onLivingDrops(final LivingDropsEvent event) { final Entity entity = event.entity; if (event.recentlyHit && canDrop(entity)) { final Double result = dropChangeCalculator.evaluate( new EnvironmentConfigurator<Double>() { @Override public void accept(Environment<Double> env) { env.setGlobalSymbol("looting", Double.valueOf(event.lootingLevel)); env.setGlobalSymbol("specialDrop", Double.valueOf(event.specialDropValue)); env.setGlobalSymbol("chance", Config.trophyDropChance); } }, new Supplier<Double>() { @Override public Double get() { final double bias = fallbackDropChance.nextDouble() / 4; final double selection = fallbackDropChance.nextDouble(); return (event.lootingLevel + bias) * Config.trophyDropChance - selection; } }); if (result > 0) { final String entityName = EntityList.getEntityString(entity); if (!Strings.isNullOrEmpty(entityName)) { Trophy mobTrophy = Trophy.TYPES.get(entityName); if (mobTrophy != null) { EntityItem drop = new EntityItem(entity.worldObj, entity.posX, entity.posY, entity.posZ, mobTrophy.getItemStack()); drop.delayBeforeCanPickup = 10; event.drops.add(drop); } } } } } private static boolean canDrop(Entity entity) { final World world = entity.worldObj; return world != null && world.getGameRules().getGameRuleBooleanValue("doMobLoot"); } }