package openblocks.enchantments;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
import com.google.common.collect.MapMaker;
import cpw.mods.fml.common.eventhandler.SubscribeEvent;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import net.minecraft.client.Minecraft;
import net.minecraft.client.settings.KeyBinding;
import net.minecraft.enchantment.EnchantmentHelper;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.entity.player.InventoryPlayer;
import net.minecraft.init.Items;
import net.minecraft.item.ItemArmor;
import net.minecraft.item.ItemStack;
import net.minecraft.util.DamageSource;
import net.minecraft.util.EntityDamageSource;
import net.minecraftforge.event.entity.living.LivingAttackEvent;
import net.minecraftforge.event.entity.living.LivingEvent.LivingJumpEvent;
import net.minecraftforge.event.entity.living.LivingFallEvent;
import openblocks.Config;
import openblocks.OpenBlocks.Enchantments;
import openmods.OpenMods;
public class ExplosiveEnchantmentsHandler {
public static final int ARMOR_HELMET = 3;
public static final int ARMOR_CHESTPIECE = 2;
public static final int ARMOR_PANTS = 1;
public static final int ARMOR_BOOTS = 0;
private final List<Integer> protectionParts = Lists.newArrayList(ARMOR_CHESTPIECE, ARMOR_HELMET, ARMOR_PANTS);
private static final double VERTICAL_FACTOR = 5;
private static final Set<String> ALLOWED_DAMAGE_SOURCE = ImmutableSet.of("arrow", "player", "mob");
private static class EnchantmentLevel {
public final double multiplier;
public final double maxHeightBonus;
public final float jumpExplosionPower;
public final float armorExplosionPower;
public final boolean isDestructive;
public final int gunpowderNeeded;
private EnchantmentLevel(double multiplier, double maxHeightBonus, float jumpExplosionPower, float armorExplosionPower, boolean isDestructive, int gunpowderNeeded) {
this.multiplier = multiplier;
this.maxHeightBonus = maxHeightBonus;
this.jumpExplosionPower = jumpExplosionPower;
this.armorExplosionPower = armorExplosionPower;
this.isDestructive = isDestructive;
this.gunpowderNeeded = gunpowderNeeded;
}
protected double calculateHeightBonus(float height) {
return Math.min(Math.sqrt(height), maxHeightBonus);
}
public double calculateMultipler(float height) {
return multiplier + calculateHeightBonus(height);
}
public void createJumpExplosion(Entity entity) {
createExplosionForEntity(entity, jumpExplosionPower, isDestructive);
}
public void createArmorExplosion(Entity entity) {
createExplosionForEntity(entity, armorExplosionPower, isDestructive);
}
}
private final static EnchantmentLevel LEVELS[] = new EnchantmentLevel[] {
null, // 1-based
new EnchantmentLevel(0.10, 5, 5, 1, false, 1),
new EnchantmentLevel(0.75, 7.5, 10, 2, false, 2),
new EnchantmentLevel(1.00, 10, 5, 4, Config.explosiveEnchantGrief, 4)
};
private static class JumpInfo {
public final EnchantmentLevel level;
public final float height;
private JumpInfo(EnchantmentLevel level, float height) {
this.level = level;
this.height = height;
}
public void modifyVelocity(Entity entity) {
double multiplier = level.calculateMultipler(height);
entity.motionX *= multiplier * VERTICAL_FACTOR;
entity.motionZ *= multiplier * VERTICAL_FACTOR;
entity.motionY *= multiplier;
}
}
public static void createExplosionForEntity(Entity entity, float power, boolean isDestructive) {
if (!entity.worldObj.isRemote) {
entity.worldObj.createExplosion(entity, entity.posX, entity.boundingBox.minY, entity.posZ, power, isDestructive);
}
}
private Map<Entity, JumpInfo> jumpBoosts = new MapMaker().weakKeys().makeMap();
private static final ItemStack gunpowder = new ItemStack(Items.gunpowder);
private static void useItems(EntityPlayer player, int gunpowderSlot, int armorSlot, int gunpowderAmout) {
if (player.capabilities.isCreativeMode) return;
final InventoryPlayer inventory = player.inventory;
ItemStack armor = inventory.armorItemInSlot(armorSlot);
armor.damageItem(1, player);
if (armor.stackSize <= 0) inventory.armorInventory[armorSlot] = null;
ItemStack resource = inventory.mainInventory[gunpowderSlot];
resource.stackSize -= gunpowderAmout;
if (resource.stackSize <= 0) inventory.mainInventory[gunpowderSlot] = null;
}
private static EnchantmentLevel tryUseEnchantment(EntityPlayer player, int armorSlot) {
final InventoryPlayer inventory = player.inventory;
ItemStack armor = inventory.armorInventory[armorSlot];
if (armor == null || !(armor.getItem() instanceof ItemArmor)) return null;
@SuppressWarnings("unchecked")
Map<Integer, Integer> enchantments = EnchantmentHelper.getEnchantments(armor);
Integer ench = enchantments.get(Enchantments.explosive.effectId);
if (ench == null || ench >= LEVELS.length) return null;
EnchantmentLevel level = LEVELS[ench];
if (level == null) return null;
for (int i = 0; i < inventory.mainInventory.length; i++) {
ItemStack stack = inventory.mainInventory[i];
if (stack != null && gunpowder.isItemEqual(stack) && stack.stackSize >= level.gunpowderNeeded) {
useItems(player, i, armorSlot, level.gunpowderNeeded);
return level;
}
}
return null;
}
private EnchantmentLevel tryUseUpperArmor(EntityPlayer player) {
Collections.shuffle(protectionParts);
for (int armorPart : protectionParts) {
EnchantmentLevel result = tryUseEnchantment(player, armorPart);
if (result != null) return result;
}
return null;
}
@SubscribeEvent
public void onFall(LivingFallEvent evt) {
final Entity e = evt.entityLiving;
if (evt.distance > 4 && !e.isSneaking() && e instanceof EntityPlayer) {
EntityPlayer player = (EntityPlayer)e;
EnchantmentLevel level = tryUseEnchantment(player, ARMOR_BOOTS);
if (level == null) return;
JumpInfo boost = new JumpInfo(level, evt.distance);
level.createJumpExplosion(player);
if (OpenMods.proxy.isClientPlayer(player)) {
// And Now, Ladies and Gentlemen!
// Logic Defying...
// Loved By Everyone...
// Possibly Buggy
// TEEERRRRRIIIIBLE HAAAAAACK!
KeyBinding.setKeyBindState(Minecraft.getMinecraft().gameSettings.keyBindJump.getKeyCode(), true);
// no, seriously, can't find better way to make jump
jumpBoosts.put(player, boost);
}
evt.setCanceled(true);
}
}
@SubscribeEvent
public void onJump(LivingJumpEvent e) {
final Entity entity = e.entity;
JumpInfo boost = jumpBoosts.remove(entity);
if (boost != null) {
boost.modifyVelocity(entity);
if (OpenMods.proxy.isClientPlayer(entity)) {
KeyBinding.setKeyBindState(Minecraft.getMinecraft().gameSettings.keyBindJump.getKeyCode(), false);
}
}
}
private static boolean checkSource(DamageSource source) {
return source instanceof EntityDamageSource && ALLOWED_DAMAGE_SOURCE.contains(source.damageType);
}
@SubscribeEvent
public void onDamage(LivingAttackEvent e) {
final Entity victim = e.entity;
if (victim instanceof EntityPlayerMP && checkSource(e.source)) {
EnchantmentLevel level = tryUseUpperArmor(((EntityPlayer)victim));
if (level != null) level.createArmorExplosion(victim);
}
}
}