package minefantasy.system;
import java.lang.annotation.Target;
import java.util.List;
import java.util.Random;
import cpw.mods.fml.client.FMLClientHandler;
import minefantasy.MineFantasyBase;
import minefantasy.api.armour.EnumArmourClass;
import minefantasy.api.armour.IArmourClass;
import minefantasy.api.armour.IArmourCustomSpeed;
import minefantasy.api.armour.IElementalResistance;
import minefantasy.api.weapon.*;
import minefantasy.block.BlockListMF;
import minefantasy.item.ElementalResistNone;
import minefantasy.item.I2HWeapon;
import minefantasy.item.ToolMaterialMedieval;
import minefantasy.item.weapon.ItemBroadsword;
import net.minecraft.block.Block;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLiving;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.EnumCreatureAttribute;
import net.minecraft.entity.SharedMonsterAttributes;
import net.minecraft.entity.effect.EntityLightningBolt;
import net.minecraft.entity.item.EntityItem;
import net.minecraft.entity.item.EntityXPOrb;
import net.minecraft.entity.monster.EntitySlime;
import net.minecraft.entity.monster.IMob;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.projectile.EntityPotion;
import net.minecraft.item.EnumArmorMaterial;
import net.minecraft.item.Item;
import net.minecraft.item.ItemArmor;
import net.minecraft.item.ItemStack;
import net.minecraft.potion.Potion;
import net.minecraft.potion.PotionEffect;
import net.minecraft.util.AxisAlignedBB;
import net.minecraft.util.DamageSource;
import net.minecraft.util.EntityDamageSource;
import net.minecraft.util.EntityDamageSourceIndirect;
import net.minecraft.util.EnumMovingObjectType;
import net.minecraft.util.MathHelper;
import net.minecraft.util.MovingObjectPosition;
import net.minecraftforge.event.entity.living.LivingAttackEvent;
import net.minecraftforge.event.entity.living.LivingHurtEvent;
public class CombatManager
{
private static Random rand = new Random();
public static void onAttack(LivingHurtEvent event)
{
EntityLivingBase target = event.entityLiving;
event.ammount = resistWithArmour(event.source, event.ammount, target);
ItemStack defense = target.getHeldItem();
if (defense != null)
{
if(defense.getItem() instanceof IWeaponSpecialBlock)
{
event.ammount = ((IWeaponSpecialBlock)defense.getItem()).blockDamage(target, event.ammount, event.source);
}
if(defense.getItem() instanceof IHitReaction)
{
((IHitReaction)defense.getItem()).onUserHit(event.source, target);
}
}
float damage = event.ammount;
int hurtTimeTemp = target.hurtTime;
int hurtResistanceTimeTemp = target.hurtResistantTime;
if (event.source instanceof EntityDamageSource && !(event.source instanceof EntityDamageSourceIndirect) && !event.source.damageType.equals("battlegearExtra"))
{
Entity entityHitter = ((EntityDamageSource) event.source).getEntity();
if (entityHitter instanceof EntityLivingBase)
{
EntityLivingBase attacker = (EntityLivingBase) entityHitter;
ItemStack weapon = attacker.getHeldItem();
if (weapon != null)
{
if(weapon.getItem() instanceof IWeightedWeapon)
{
float power = ((IWeightedWeapon)weapon.getItem()).getBlockFailureChance();
if(target instanceof EntityPlayer && power > 0.0F)
{
if(!target.worldObj.isRemote && defense != null && ((EntityPlayer)target).isBlocking())
{
int itemdam = (int)(Math.floor(damage * power * 2));
defense.damageItem(itemdam, target);
if(target.getRNG().nextFloat() < power)
{
entityDropItem(target, defense, 0.2F);
target.setCurrentItemOrArmor(0, null);
}
}
}
}
if(weapon.getItem() instanceof ICustomDamager)
{
event.ammount = damage = ((ICustomDamager)weapon.getItem()).getHitDamage(weapon);
}
if(weapon.getItem() instanceof IWeaponWeakArmour)
{
float multiplier = ((IWeaponWeakArmour)weapon.getItem()).getArmourPower(weapon);
event.ammount = damage = applyArmorCalculations(multiplier, target, event.source, damage);
}
if(weapon.getItem() instanceof IWeaponPenetrateArmour)
{
float dam = ((IWeaponPenetrateArmour)weapon.getItem()).getAPDamage();
event.ammount -= dam;
damageWithBonus(target, DamageSourceAP.blunt, damage, dam);
if(((IWeaponPenetrateArmour)weapon.getItem()).buffDamage())
{
float bonus = ((IWeaponPenetrateArmour)weapon.getItem()).getArmourDamageBonus()-1.0F;
if(bonus > 0.0F)
{
int AD = (int)((damage + dam) * bonus);
if(target instanceof EntityPlayer)
{
((EntityPlayer)target).inventory.damageArmor(AD);
}
}
}
}
if(attacker.isSneaking() && TacticalManager.isDetected(target, attacker) && TacticalManager.isFlankedBy(attacker, (EntityLivingBase)target, 90))
{
float bonus = 1.0F;
if(weapon.getItem() instanceof IStealthWeapon)
{
bonus = ((IStealthWeapon)weapon.getItem()).getBackstabModifier();
}
event.ammount = damage = applySneakAttack(attacker, target, damage * bonus);
}
if(attacker.fallDistance > 3.0F && attacker.fallDistance < 23.0F && weapon.getItem() instanceof IStealthWeapon)
{
if(((IStealthWeapon)weapon.getItem()).canDropAttack())
{
float bonus = ((IStealthWeapon)weapon.getItem()).getDropModifier();
float dam = (attacker.fallDistance-3.0F) * bonus;
event.ammount = damage = applyDropAttack(attacker, target, damage, bonus);
}
}
if (weapon.getItem() instanceof IWeaponSpecial)
{
((IWeaponSpecial) weapon.getItem()).onHit(damage, weapon, target, attacker);
}
if (weapon.getItem() instanceof IWeaponCustomSpeed)
{
hurtTimeTemp += ((IWeaponCustomSpeed)weapon.getItem()).getHitTime(weapon, target);
hurtResistanceTimeTemp += ((IWeaponCustomSpeed)weapon.getItem()).getHitTime(weapon, target);
}
}
EventManagerMF.makeHitSound(weapon, target);
}
}
target.hurtResistantTime = hurtResistanceTimeTemp;
target.hurtTime = hurtTimeTemp;
}
public static float applySneakAttack(Entity attacker, Entity target, float dam)
{
target.playSound("minefantasy:Weapon.crit", dam/2F, 1.0F);
if(attacker instanceof EntityPlayer)
{
((EntityPlayer)attacker).onCriticalHit(target);
}
return dam;
}
public static void attackSpecial(Entity attacker, Entity target, float dam)
{
target.attackEntityFrom(new EntityDamageSource("battlegearSpecial", attacker), dam);
}
public static float applyDropAttack(EntityLivingBase attacker, Entity target, float dam, float bonus)
{
target.playSound("minefantasy:Weapon.crit", dam*2F, 1.0F);
if(attacker instanceof EntityPlayer)
{
((EntityPlayer)attacker).onCriticalHit(target);
}
attacker.getHeldItem().damageItem((int)(bonus/2), attacker);
attacker.setPositionAndUpdate(target.posX, target.posY, target.posZ);
attacker.motionY = 0;
attacker.fallDistance = 0;
return dam*bonus;
}
protected static float applyArmorCalculations(float power, EntityLivingBase target, DamageSource source, float damage)
{
if (!source.isUnblockable())
{
int i = 25 - (int)(target.getTotalArmorValue() * power);
float f1 = damage * (float)i;
damage = f1 / 25.0F;
}
return damage;
}
public static float getMovementSpeedModifier(EntityLivingBase entity)
{
return getMovementSpeedModifier(entity, true);
}
public static float getMovementSpeedModifier(EntityLivingBase entity, boolean includeWep)
{
float r = 1F;
float AC0 = CombatManager.getMoveSpeedFor(entity, 0);
r -= (float)CombatManager.getArmourFractionOfTotal(AC0, 4);
float AC1 = CombatManager.getMoveSpeedFor(entity, 1);
r -= (float)CombatManager.getArmourFractionOfTotal(AC1, 7);
float AC2 = CombatManager.getMoveSpeedFor(entity, 2);
r -= (float)CombatManager.getArmourFractionOfTotal(AC2, 8);
float AC3 = CombatManager.getMoveSpeedFor(entity, 3);
r -= (float)CombatManager.getArmourFractionOfTotal(AC3, 5);
if(includeWep)
{
r *= slowdownHeavyWeapon(entity);
}
return r;
}
public static int getAntisprintArmours(EntityLivingBase entity)
{
int r = 0;
EnumArmourClass AC0 = CombatManager.getClassInSlot(entity, 0);
r += AC0.canSprintIn() ? 0 : 1;
EnumArmourClass AC1 = CombatManager.getClassInSlot(entity, 1);
r += AC1.canSprintIn() ? 0 : 1;
EnumArmourClass AC2 = CombatManager.getClassInSlot(entity, 2);
r += AC2.canSprintIn() ? 0 : 1;
EnumArmourClass AC3 = CombatManager.getClassInSlot(entity, 3);
r += AC3.canSprintIn() ? 0 : 1;
return r;
}
public static float getArmourExaustModifier(EntityLivingBase player)
{
float r = 0F;
EnumArmourClass AC0 = CombatManager.getClassInSlot(player, 0);
r += (float)CombatManager.getArmourFractionOfTotal(AC0.getExaustion(), 4);
EnumArmourClass AC1 = CombatManager.getClassInSlot(player, 1);
r += (float)CombatManager.getArmourFractionOfTotal(AC1.getExaustion(), 7);
EnumArmourClass AC2 = CombatManager.getClassInSlot(player, 2);
r += (float)CombatManager.getArmourFractionOfTotal(AC2.getExaustion(), 8);
EnumArmourClass AC3 = CombatManager.getClassInSlot(player, 3);
r += (float)CombatManager.getArmourFractionOfTotal(AC3.getExaustion(), 5);
return r;
}
private static float getMoveSpeedFor(EntityLivingBase entity, int i)
{
EnumArmourClass AC = CombatManager.getClassInSlot(entity, i);
float r = AC.getSpeedReduction();
ItemStack armour = armourInSlot(entity, i);
if(armour != null && armour.getItem() != null)
{
if(armour.getItem() instanceof IArmourCustomSpeed)
{
r = 1F - ((IArmourCustomSpeed)armour.getItem()).getMoveSpeed(armour);
}
}
return r;
}
public static double getArmourFractionOfTotal(double total, int armour)
{
return (total/24)*armour;
}
public static ItemStack armourInSlot(EntityLivingBase ent, int i) {
return ent.getCurrentItemOrArmor(i+1);
}
public static EnumArmourClass getClassInSlot(EntityLivingBase entity, int i) {
return TacticalManager.getClassFor(armourInSlot(entity, i));
}
private static float slowdownHeavyWeapon(EntityLivingBase entity) {
float wp = 1F;
ItemStack held = entity.getHeldItem();
if(held != null && held.getItem() instanceof IWeaponMobility)
{
float minus = ((IWeaponMobility)held.getItem()).getSpeedWhenEquipped();
if(wp > minus)wp = minus;
}
if(entity instanceof EntityPlayer)
{
EntityPlayer player = (EntityPlayer)entity;
for(int a = 0; a < 9; a ++)
{
ItemStack slot = player.inventory.mainInventory[a];
if( slot != null && slot.getItem() instanceof IWeaponMobility)
{
float minus = ((IWeaponMobility)slot.getItem()).getSpeedWhenEquipped();
if(wp > minus)wp = minus;
}
}
}
else
{
ItemStack s = entity.getHeldItem();
if( s != null && s.getItem() instanceof IWeaponMobility)
{
float minus = ((IWeaponMobility)s.getItem()).getSpeedWhenEquipped();
if(wp > minus)wp = minus;
}
}
if(wp < 0.1) return 0.1F;
if(cfg.disableWeight && wp < 1.0F)
{
return 1.0F;
}
return wp;
}
/**
* Damages an entity but will not register as a kill (meaning enemies will not die twice)
*/
public static void damageWithBonus(EntityLivingBase target, DamageSource source, float damage, float bonus)
{
if(bonus < target.getHealth())
{
target.attackEntityFrom(DamageSourceAP.blunt, bonus+damage);
if(!target.worldObj.isRemote)
{
System.out.println("Damage");
}
}
else
{
if(!target.worldObj.isRemote)
{
target.setHealth(-1F); // Over here it sets health to <0 killing the entity, but not registering as it's own kill
}
}
}
public static void entityDropItem(Entity entity, ItemStack drop, float range)
{
if (drop.stackSize == 0)
{
return;
}
else
{
EntityItem entityitem = new EntityItem(entity.worldObj, entity.posX, entity.posY + (double)range, entity.posZ, drop);
entityitem.delayBeforeCanPickup = 50;
if (entity.captureDrops)
{
entity.capturedDrops.add(entityitem);
}
else
{
entity.worldObj.spawnEntityInWorld(entityitem);
}
}
}
private static float resistWithArmour(DamageSource source, float dam, EntityLivingBase target)
{
for(int a = 1; a < 5; a ++)
{
ItemStack piece = target.getCurrentItemOrArmor(a);
if(piece != null && piece.getItem() instanceof IElementalResistance)
{
IElementalResistance resist = (IElementalResistance)piece.getItem();
if(source.isFireDamage())
{
dam *= resist.fireResistance();
}
}
}
return dam;
}
}