package openblocks.enchantments;
import com.google.common.collect.Lists;
import cpw.mods.fml.common.eventhandler.SubscribeEvent;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Random;
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.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.ChatComponentTranslation;
import net.minecraft.world.World;
import net.minecraftforge.common.IExtendedEntityProperties;
import net.minecraftforge.event.entity.EntityEvent;
import net.minecraftforge.event.entity.living.LivingHurtEvent;
import openblocks.OpenBlocks.Enchantments;
import openblocks.api.IFlimFlamDescription;
import openblocks.enchantments.flimflams.FlimFlamRegistry;
import openmods.Log;
public class FlimFlamEnchantmentsHandler {
public static final String LUCK_PROPERTY = "OpenBlocks-Luck";
public static final int LUCK_MARGIN = -30;
public static final int EFFECT_DELAY = 20 * 15; // 15s cooldown
private static final Random RANDOM = new Random();
private static class Luck implements IExtendedEntityProperties {
public int luck;
public int cooldown;
public boolean forceNext;
@Override
public void saveNBTData(NBTTagCompound entityTag) {
entityTag.setInteger(LUCK_PROPERTY, luck);
}
@Override
public void loadNBTData(NBTTagCompound entityTag) {
luck = entityTag.getInteger(LUCK_PROPERTY);
}
@Override
public void init(Entity entity, World world) {}
}
private static Luck getProperty(Entity entity) {
IExtendedEntityProperties prop = entity.getExtendedProperties(LUCK_PROPERTY);
return (prop instanceof Luck)? (Luck)prop : null;
}
@SubscribeEvent
public void onEntityConstruct(EntityEvent.EntityConstructing evt) {
if (evt.entity instanceof EntityPlayer) evt.entity.registerExtendedProperties(LUCK_PROPERTY, new Luck());
}
@SubscribeEvent
public void onDamage(LivingHurtEvent e) {
if (!(e.entityLiving instanceof EntityPlayer)) return;
if (e.entityLiving.worldObj.isRemote) return;
final EntityPlayer targetPlayer = (EntityPlayer)e.entityLiving;
if (e.source == null) return;
final Entity damageSource = e.source.getEntity();
if (!(damageSource instanceof EntityPlayer)) return;
final EntityPlayer sourcePlayer = (EntityPlayer)damageSource;
// flim flam yerself?
if (sourcePlayer == targetPlayer) return;
final int sourceFlimFlam = getFlimFlamToolLevel(sourcePlayer);
final int targetFlimFlam = getFlimFlamArmorLevel(targetPlayer);
// armor is less effective, since we can have more levels
final int flimFlamDiff = targetFlimFlam / 3 - sourceFlimFlam;
final EntityPlayer flimFlamTarget;
final int flimFlamsToApply;
if (flimFlamDiff == 0) return;
if (flimFlamDiff > 0) {
// target is better protected
flimFlamTarget = sourcePlayer;
flimFlamsToApply = flimFlamDiff;
} else {
flimFlamTarget = targetPlayer;
flimFlamsToApply = -flimFlamDiff;
}
Luck victimLuck = getProperty(flimFlamTarget);
if (victimLuck != null) {
for (int i = 0; i < flimFlamsToApply; i++) {
int roll = rollD20();
// critical
if (roll == 20) victimLuck.forceNext = true;
victimLuck.luck -= roll;
}
if (victimLuck.luck < LUCK_MARGIN) victimLuck.forceNext = true;
}
}
private static int rollD20() {
return RANDOM.nextInt(20) + 1;
}
public static void deliverKarma(EntityPlayerMP player) {
if (player.isDead) return;
Luck property = getProperty(player);
if (property == null || !canFlimFlam(property)) return;
final int luck = property.luck;
int totalWeight = 0;
List<IFlimFlamDescription> selectedEffects = Lists.newArrayList();
for (IFlimFlamDescription effectMeta : FlimFlamRegistry.instance.getFlimFlams())
if (effectMeta.canApply(luck) && !FlimFlamRegistry.BLACKLIST.isBlacklisted(effectMeta)) {
selectedEffects.add(effectMeta);
totalWeight += effectMeta.weight();
}
if (selectedEffects.isEmpty()) return;
Collections.shuffle(selectedEffects);
while (!selectedEffects.isEmpty()) {
final int selectedWeight = RANDOM.nextInt(totalWeight);
int currentWeight = 0;
Iterator<IFlimFlamDescription> it = selectedEffects.iterator();
while (it.hasNext()) {
final IFlimFlamDescription effectMeta = it.next();
currentWeight += effectMeta.weight();
if (selectedWeight <= currentWeight) {
try {
if (effectMeta.action().execute(player)) {
property.luck -= effectMeta.cost();
Log.debug("Player %s flim-flammed with %s, current luck: %s", player, effectMeta.name(), property.luck);
if (!effectMeta.isSilent()) player.addChatMessage(new ChatComponentTranslation("openblocks.flim_flammed"));
return;
}
} catch (Throwable t) {
Log.warn(t, "Error during flimflam '%s' execution", effectMeta.name());
}
totalWeight -= effectMeta.weight();
it.remove();
break;
}
}
}
}
public static int getLuck(EntityPlayer player) {
Luck property = getProperty(player);
return property != null? property.luck : 0;
}
public static int modifyLuck(EntityPlayer player, int amount) {
Luck property = getProperty(player);
if (property == null) return 0;
property.luck += amount;
return property.luck;
}
private static boolean canFlimFlam(Luck property) {
if (property.forceNext) {
property.forceNext = false;
property.cooldown = EFFECT_DELAY;
return true;
}
if (property.luck > -LUCK_MARGIN || property.cooldown-- > 0) return false;
property.cooldown = EFFECT_DELAY;
double probability = 0.75 * 2.0 * Math.abs(Math.atan(property.luck / 250.0) / Math.PI);
double r = RANDOM.nextDouble();
return r < probability;
}
private static int getFlimFlamToolLevel(EntityPlayer player) {
return getFlimFlamLevel(player.getHeldItem());
}
private static int getFlimFlamArmorLevel(EntityPlayer player) {
int sum = 0;
for (ItemStack stack : player.inventory.armorInventory) {
sum += getFlimFlamLevel(stack);
}
return sum;
}
@SuppressWarnings("unchecked")
private static int getFlimFlamLevel(ItemStack stack) {
if (stack == null) return 0;
Map<Integer, Integer> enchantments = EnchantmentHelper.getEnchantments(stack);
Integer result = enchantments.get(Enchantments.flimFlam.effectId);
return result != null? result : 0;
}
}