package minefantasy.mf2.mechanics;
import java.util.Map;
import java.util.Random;
import minefantasy.mf2.api.armour.CogworkArmour;
import minefantasy.mf2.api.armour.IElementalResistance;
import minefantasy.mf2.api.helpers.ArmourCalculator;
import minefantasy.mf2.api.helpers.ArrowEffectsMF;
import minefantasy.mf2.api.helpers.CustomToolHelper;
import minefantasy.mf2.api.helpers.TacticalManager;
import minefantasy.mf2.api.knowledge.ResearchLogic;
import minefantasy.mf2.api.material.CustomMaterial;
import minefantasy.mf2.api.rpg.RPGElements;
import minefantasy.mf2.api.rpg.SkillList;
import minefantasy.mf2.api.stamina.StaminaBar;
import minefantasy.mf2.api.tier.IToolMaterial;
import minefantasy.mf2.api.weapon.IDamageModifier;
import minefantasy.mf2.api.weapon.IKnockbackWeapon;
import minefantasy.mf2.api.weapon.IParryable;
import minefantasy.mf2.api.weapon.IPowerAttack;
import minefantasy.mf2.api.weapon.ISpecialEffect;
import minefantasy.mf2.api.weapon.IWeaponSpeed;
import minefantasy.mf2.api.weapon.IWeightedWeapon;
import minefantasy.mf2.config.ConfigArmour;
import minefantasy.mf2.config.ConfigExperiment;
import minefantasy.mf2.config.ConfigStamina;
import minefantasy.mf2.config.ConfigWeapon;
import minefantasy.mf2.entity.Shockwave;
import minefantasy.mf2.item.weapon.ItemBattleaxeMF;
import minefantasy.mf2.item.weapon.ItemDagger;
import minefantasy.mf2.item.weapon.ItemKatanaMF;
import minefantasy.mf2.item.weapon.ItemWaraxeMF;
import minefantasy.mf2.item.weapon.ItemWeaponMF;
import minefantasy.mf2.knowledge.KnowledgeListMF;
import minefantasy.mf2.material.BaseMaterialMF;
import minefantasy.mf2.network.packet.ParryPacket;
import minefantasy.mf2.util.MFLogUtil;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLiving;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.item.EntityEnderPearl;
import net.minecraft.entity.monster.EntitySkeleton;
import net.minecraft.entity.monster.EntityZombie;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.projectile.EntityArrow;
import net.minecraft.init.Items;
import net.minecraft.item.Item.ToolMaterial;
import net.minecraft.item.ItemStack;
import net.minecraft.potion.Potion;
import net.minecraft.potion.PotionEffect;
import net.minecraft.util.DamageSource;
import net.minecraft.util.EntityDamageSource;
import net.minecraft.util.EntityDamageSourceIndirect;
import net.minecraft.world.World;
import net.minecraft.world.WorldServer;
import net.minecraftforge.common.ISpecialArmor;
import net.minecraftforge.event.entity.living.LivingAttackEvent;
import net.minecraftforge.event.entity.living.LivingEvent.LivingJumpEvent;
import net.minecraftforge.event.entity.living.LivingEvent.LivingUpdateEvent;
import net.minecraftforge.event.entity.living.LivingHurtEvent;
import cpw.mods.fml.common.eventhandler.SubscribeEvent;
public class CombatMechanics
{
public static final String parryCooldownNBT = "MF_Parry_Cooldown";
public static final String posthitCooldownNBT = "MF_PostHit";
private static Random rand = new Random();
public static final float specialUndeadModifier = 2.0F;
public static final float specialDragonModifier = 0.5F;
public static final float specialWerewolfModifier = 8.0F;
public static boolean swordSkeleton = true;
protected float jumpEvade_cost = 30;
protected float evade_cost = 10;
@SubscribeEvent
public void initAttack(LivingAttackEvent event)
{
/*
if(event.source == DamageSource.fall && event.entityLiving instanceof EntityPlayer && RPGElements.isSystemActive)
{
SkillList.acrobatics.addXP((EntityPlayer) event.entityLiving, (int)event.ammount+1);
}
if(RPGElements.isSystemActive && event.entityLiving instanceof EntityPlayer && !event.source.isUnblockable())
{
for(int a = 0; a < 4; a++)
{
ItemStack piece = event.entityLiving.getEquipmentInSlot(a+1);
if(piece != null)
{
int AC = ArmourCalculator.getArmourClass(piece).equalsIgnoreCase("heavy") ? 2 : ArmourCalculator.getArmourClass(piece).equalsIgnoreCase("light") ? 0 : 1;
Skill skill = (AC == 2) ? SkillList.heavyarmour : (AC == 0) ? SkillList.lightarmour : SkillList.mediumarmour;
skill.addXP((EntityPlayer) event.entityLiving, (int)(event.ammount/5F));
}
}
}
*/
EntityLivingBase hitter = getHitter(event.source);
int spd = EventManagerMF.getHitspeedTime(hitter);
if(hitter != null && !hitter.worldObj.isRemote)
{
if(spd > 0 && !(event.entityLiving instanceof EntityPlayer))
{ event.setCanceled(true);
return;
}
}
DamageSource src = event.source;
EntityLivingBase hit = event.entityLiving;
World world = hit.worldObj;
float damage = modifyDamage(src, world, hit, event.ammount, false);
if(event.source.isProjectile() && !event.source.isFireDamage() && damage < event.ammount && hit.getTotalArmorValue() > 0)//only if dam has been reduced
{
if(ConfigArmour.resistArrow && !event.isCanceled() && damage <= 0)//TacticalManager.resistArrow(event.entityLiving, event.source, damage))
{
if(event.source.getSourceOfDamage() != null && !event.source.getSourceOfDamage().getEntityData().hasKey("arrowDeflectMF") && !(event.source.getEntity() instanceof EntityEnderPearl))
{
event.source.getSourceOfDamage().getEntityData().setBoolean("arrowDeflectMF", true);
event.entityLiving.worldObj.playSoundAtEntity(event.entityLiving, "random.break", 1.0F, 0.5F);
}
event.setCanceled(true);
}
}
if(damage <= 0)
{
event.setCanceled(true);
}
if(hitter != null && hitter instanceof EntityLivingBase)
{
int hitTime = 5;
if(hitter.getHeldItem() != null)
{
ItemStack weapon = hitter.getHeldItem();
if(weapon.getItem() instanceof IWeaponSpeed)
{
hitTime += ((IWeaponSpeed)weapon.getItem()).modifyHitTime(hitter, weapon);
}
}
if(hitTime > 0)
EventManagerMF.setHitTime(hitter, hitTime);
}
}
/**
* gets the melee hitter
*/
private EntityLivingBase getHitter(DamageSource source)
{
if(source != null && source.getEntity() != null && source.getEntity() == source.getSourceOfDamage() && source.getEntity() instanceof EntityLivingBase)
{
return (EntityLivingBase) source.getEntity();
}
return null;
}
@SubscribeEvent
public void onHit(LivingHurtEvent event)
{
DamageSource src = event.source;
EntityLivingBase hit = event.entityLiving;
if(src != null && src == DamageSource.fall)
{
onFall(hit, event.ammount);
}
World world = hit.worldObj;
float damage = modifyDamage(src, world, hit, event.ammount, true);
if(damage > 0 && hit.isSprinting())
{
hit.setSprinting(false);
}
//TODO: Zombie armour
if(event.entityLiving.getEntityData().hasKey(MonsterUpgrader.zombieArmourNBT) && event.entityLiving instanceof EntityZombie)
{
float percent = 1.0F;
ItemStack[] armours = new ItemStack[4];
for(int a = 1; a < 5; a ++)
{
armours[a-1]=event.entityLiving.getEquipmentInSlot(a);
}
damage = ISpecialArmor.ArmorProperties.ApplyArmor(event.entityLiving, armours, event.source, damage);
}
//TODO: Stick arrows (EXPERIMENTAL)
if(ConfigExperiment.stickArrows && event.source.getSourceOfDamage() != null && event.source.getSourceOfDamage() instanceof EntityArrow)
{
if(!event.entity.worldObj.isRemote)
{
ArrowEffectsMF.stickArrowIn(event.entity, ArrowEffectsMF.getDroppedArrow(event.source.getSourceOfDamage()), event.source.getSourceOfDamage());
}
}
if(damage > 0)
{
onOfficialHit(src, hit, damage);
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;
StaminaMechanics.onAttack(attacker, hit);
ItemStack weapon = attacker.getHeldItem();
HitSoundGenerator.makeHitSound(weapon, event.entityLiving);
}
}
}
event.ammount = damage;
}
private void onFall(EntityLivingBase fallen, float height)
{
float weight = ArmourCalculator.getTotalWeightOfWorn(fallen, false);
if(weight > 100)
{
weight -= 100F;
float power = (height/4F) * (weight/100F);
newShockwave(fallen, fallen.posX, fallen.posY, fallen.posZ, power, false, true);
}
}
public Shockwave newShockwave(Entity source, double x, double y, double z, float power, boolean fire, boolean smoke)
{
Shockwave explosion = new Shockwave("humanstomp", source.worldObj, source, x, y, z, power);
explosion.isFlaming = fire;
explosion.isSmoking = smoke;
explosion.initiate();
explosion.decorateWave(true);
return explosion;
}
private float modifyDamage(DamageSource src, World world, EntityLivingBase hit, float dam, boolean properHit)
{
Entity source = src.getSourceOfDamage();
Entity hitter = src.getEntity();
if(properHit && hit instanceof EntityPlayer)
{
dam = modifyPlayerDamage((EntityPlayer)hit, dam);
}
if(source != null && hitter != null && hitter instanceof EntityLivingBase)
{
dam = modifyUserHitDamage(dam, (EntityLivingBase)hitter, source, hitter == source, hit, properHit);
}
if(src.isExplosion() && isSkeleton(hit))
{
dam *= 5F;
}
//TODO: Elemental resistance
dam *= TacticalManager.getResistance(hit, src);
if(src.isFireDamage())
{
if(dam <= 0.0F)
{
hit.extinguish();
}
}
dam = onUserHit(hit, hitter, src, dam, properHit);
return dam;
}
private boolean isSkeleton(Entity target)
{
return target instanceof EntitySkeleton;
}
//TODO: damage modifier
private float modifyUserHitDamage(float dam, EntityLivingBase user, Entity source, boolean melee, Entity target, boolean properHit)
{
dam = modifyMobDamage(user, dam);
//Power Attack
if(melee)
{
int powerAttack = initPowerAttack(user, target, properHit);
if(powerAttack == 1)
{
dam *= (2F/1.5F);
onPowerAttack(dam, user, target, properHit);
if(isSkeleton(target))
{
dam *= 1.5F;
if(properHit)
{
if(rand.nextInt(2) == 0)
{
target.entityDropItem(new ItemStack(Items.bone), 0.5F);
}
}
}
}
if(powerAttack == -1)
{
dam /= 2F;
}
/*
if(RPGElements.isSystemActive && user instanceof EntityPlayer)
{
WeaponClass WC = WeaponClass.findClassForAny(user.getHeldItem());
if(WC != null)
{
float mod = RPGElements.getWeaponModifier((EntityPlayer) user, WC.parentSkill);
MFLogUtil.logDebug("Weapon Class: " + WC.name + ", mod = " + mod);
dam *= mod;
}
}
*/
}
if(user instanceof EntityLivingBase)
{
EntityLivingBase player = user;
//TODO: Stamina Traits
if(StaminaBar.isSystemActive)
{
if(StaminaBar.getStaminaValue(player) <= 0)
{
dam *= ConfigStamina.weaponDrain;
}
}
}
if(user.hurtResistantTime > 12)
{
dam *= 0.5F;
}
ItemStack weapon = user.getHeldItem();
if(weapon != null)
{
if(weapon.getItem() instanceof IDamageModifier)
{
//TODO: IDamageModifier, this mods the damage for weapons
dam = ((IDamageModifier)weapon.getItem()).modifyDamage(weapon, user, target, dam, properHit);
}
CustomMaterial material = CustomToolHelper.getCustomMetalMaterial(weapon);
if(material != null && material.name.equalsIgnoreCase("silver"))
{
dam = hurtUndead(user, target, dam, properHit);
}
if(!weapon.getUnlocalizedName().contains("dragonforged") && target instanceof EntityLivingBase && TacticalManager.isDragon((EntityLivingBase)target))
{
dam *= specialDragonModifier;
}
}
return dam;
}
private void onPowerAttack(float dam, EntityLivingBase user, Entity target, boolean properHit)
{
ItemStack weapon = user.getHeldItem();
int ticks = 20;
if(weapon != null && weapon.getItem() instanceof IPowerAttack)
{
((IPowerAttack)weapon.getItem()).onPowerAttack(dam, user, target, properHit);
ticks = ((IPowerAttack)weapon.getItem()).getParryModifier(weapon, user, target);
}
if(target instanceof EntityLivingBase)
{
if(ticks > getParryCooldown((EntityLivingBase)target))
{
setParryCooldown((EntityLivingBase)target, ticks);
}
}
if(!user.worldObj.isRemote)
{
user.addPotionEffect(new PotionEffect(Potion.digSlowdown.id, 20, 5));
user.addPotionEffect(new PotionEffect(Potion.moveSlowdown.id, 20, 10));
}
if(user instanceof EntityPlayer)
{
TacticalManager.lungeEntity(user, target, 0.5F, 0F);
TacticalManager.throwPlayerOffBalance((EntityPlayer) user, 0.5F, true);
}
target.worldObj.playSoundAtEntity(target, "minefantasy2:weapon.critical", 1.0F, 1.0F);
}
private static final float power_attack_base = 25F;
/**
* 0 = false
* 1 = true
* -1 = failure
*/
private static int initPowerAttack(EntityLivingBase user, Entity target, boolean properHit)
{
if(!canExecutePower(user))
{
return 0;
}
if(StaminaBar.isSystemActive && StaminaBar.doesAffectEntity(user))
{
float points = power_attack_base * (StaminaBar.getBaseDecayModifier(user, true, true)*0.5F + 0.5F);
if(StaminaBar.isStaminaAvailable(user, points, properHit))
{
if(properHit)
{
ItemWeaponMF.applyFatigue(user, points);
}
return getPostHitCooldown(user) > 0 ? -1 : 1;
}
else
{
return 0;
}
}
return 1;
}
private static boolean canExecutePower(EntityLivingBase user)
{
if(user.isInWater())
{
return false;
}
if(user instanceof EntityPlayer)
{
if(!isFightStance(user))return false;
}
return user.fallDistance > 0 && !user.isOnLadder();
}
private static boolean isFightStance(EntityLivingBase user)
{
return user.isSneaking();
}
private float modifyMobDamage(EntityLivingBase user, float dam)
{
if(user instanceof EntityZombie && user.isChild())
{
dam *= 0.65F;
}
return dam + getStrengthEnhancement(user);
}
private boolean isMaterialUndeadKiller(ItemStack weapon, ToolMaterial material)
{
CustomMaterial mat = CustomToolHelper.getCustomMetalMaterial(weapon);
if(mat != null && mat.name.equalsIgnoreCase("silver"))
{
return true;
}
return material == BaseMaterialMF.silver.getToolConversion() || material == BaseMaterialMF.ornate.getToolConversion();
}
private float hurtUndead(Entity entityHitting, Entity entityHit, float dam, boolean properHit)
{
if(entityHit instanceof EntityLivingBase && TacticalManager.isUnholyCreature((EntityLivingBase)entityHit))
{
EntityLivingBase living = (EntityLivingBase)entityHit;
dam *= specialUndeadModifier;
if(properHit)
{
entityHit.playSound("random.fizz", 0.5F, 0.5F);
living.addPotionEffect(new PotionEffect(Potion.weakness.id, 1200, 2));
if(rand.nextInt(10) == 0)
{
living.setFire(3);
}
if(living.getHealth() <= living.getHealth()/2F && rand.nextInt(20) == 0)
{
dam *= 100F;
living.worldObj.createExplosion(living, living.posX, living.posY+living.getEyeHeight(), living.posZ, 0.0F, false);
}
}
}
if(entityHit.getClass().getName().contains("Werewolf"))
{
dam *= specialWerewolfModifier;
if(properHit)
{
entityHit.playSound("random.fizz", 0.6F, 0.5F);
}
}
return dam;
}
private void onOfficialHit(DamageSource src, EntityLivingBase target, float damage)
{
Entity source = src.getSourceOfDamage();
Entity hitter = src.getEntity();
if(source != null && hitter != null && hitter instanceof EntityLivingBase)
{
if(source == hitter)
{
EntityLivingBase user = (EntityLivingBase)hitter;
ItemStack weapon = user.getHeldItem();
if(weapon != null)
{
onWeaponHit(user, weapon, target, damage);
}
if(RPGElements.isSystemActive && user instanceof EntityPlayer )
{
SkillList.combat.addXP((EntityPlayer)user, (int)(damage/5F));
}
}
else
{
if(source instanceof EntityArrow && src.isProjectile())
{
onArrowHit(source, target, hitter, damage);
}
}
}
CombatMechanics.setPostHitCooldown(target, 10);
}
private void onWeaponHit(EntityLivingBase user, ItemStack weapon, Entity target, float dam)
{
if(target instanceof EntityLivingBase && weapon.getItem() instanceof ISpecialEffect)
{
((ISpecialEffect)weapon.getItem()).onProperHit(user, weapon, target, dam);
}
if(weapon.getItem() instanceof IWeaponSpeed)
{
target.hurtResistantTime += ((IWeaponSpeed)weapon.getItem()).modifyHitTime(user, weapon);
}
if(weapon.getItem() instanceof IKnockbackWeapon)
{
float kb = ((IKnockbackWeapon)weapon.getItem()).getAddedKnockback(user, weapon);
if(kb > 0)
{
TacticalManager.knockbackEntity(target, user, kb, 0F);
}
}
if (ConfigWeapon.useBalance && user instanceof EntityPlayer)
{
applyBalance((EntityPlayer)user);
}
}
private void onArrowHit(Entity arrow, Entity target, Entity shooter, float damage)
{
/*
if(RPGElements.isSystemActive && shooter instanceof EntityPlayer)
{
SkillList.archery.addXP((EntityPlayer) shooter, (int)damage);
}
*/
}
protected static void performEffects(Map<PotionEffect, Float> map, EntityLivingBase entityHit)
{
double roll = Math.random();
if(map == null || map.isEmpty())
{
return;
}
for(PotionEffect effect:map.keySet())
{
//add effects if they aren't already applied, with corresponding chance factor
if(!entityHit.isPotionActive(effect.getPotionID()) && map.get(effect) > roll)
{
entityHit.addPotionEffect(new PotionEffect(effect));
}
}
}
private static boolean debugParry = true;
private static final float parryFatigue = 5F;
private float onUserHit(EntityLivingBase user, Entity entityHitting, DamageSource source, float dam, boolean properHit)
{
ItemStack weapon = user.getHeldItem();
if((properHit || source.isProjectile()) && weapon != null && !source.isUnblockable() &&!source.isExplosion())
{
float threshold = 10;//DEFAULT PARRY THRESHOLD
float weaponFatigue = 2.0F;//DEFAULT FATIGUE
int ticks = 18;//DEFAULT TICKS
IParryable parry = null;
if(weapon.getItem() instanceof IParryable)
{
parry = (IParryable)weapon.getItem();
ticks = parry.getParryCooldown(source, dam, weapon);
threshold = parry.getMaxDamageParry(user, weapon);
weaponFatigue = parry.getParryStaminaDecay(source, weapon);
}
if(StaminaBar.isSystemActive && !StaminaBar.isAnyStamina(user, false))
{
threshold /= 2;
}
threshold *= TacticalManager.getHighgroundModifier(user, entityHitting, 1.15F);
if(ArmourCalculator.advancedDamageTypes && !user.worldObj.isRemote)
{
threshold = ArmourCalculator.adjustACForDamage(source, threshold, 1.0F, 0.75F, 0.5F);
}
if(debugParry && !user.worldObj.isRemote){MFLogUtil.logDebug("Init Parry: Damage = " + dam + " Threshold = " + threshold);}
//USED FOR PARRYING its harder to block arrows
if(TacticalManager.canParry(source, user, entityHitting, weapon))
{
float previousDam = dam;
dam = Math.max(0F, dam - threshold);
if(debugParry && !user.worldObj.isRemote){MFLogUtil.logDebug("Parried: dam = " + dam);}
if(properHit || dam <= 0)
{
user.hurtResistantTime = user.maxHurtResistantTime;
user.hurtTime = 0;
int result = onParry(source, user, entityHitting, dam, previousDam, parry);
if(result == 1)
{
dam = 0;
}
if(StaminaBar.isSystemActive && StaminaBar.doesAffectEntity(user) && !StaminaBar.isAnyStamina(user, false))
{
ticks *= 3;
}
if(ticks > getParryCooldown(user))
{
setParryCooldown(user, ticks);
}
ItemWeaponMF.applyFatigue(user, TacticalManager.getHighgroundModifier(user, entityHitting, 2.0F)*(dam+1F)*parryFatigue*weaponFatigue);
if(parry == null)
{
user.worldObj.playSoundAtEntity(user, getDefaultParrySound(weapon), 1.0F, 1.25F + (rand.nextFloat()*0.5F));
}
else if(!parry.playCustomParrySound(user, entityHitting, weapon))
{
user.worldObj.playSoundAtEntity(user, "mob.zombie.metal", 1.0F, 1.25F + (rand.nextFloat()*0.5F));
}
if(user instanceof EntityPlayer)
{
((EntityPlayer)user).stopUsingItem();
ItemWeaponMF.setParry(weapon, 20);
}
if(entityHitting != null && entityHitting instanceof EntityLivingBase)
{
EntityLivingBase hitter = (EntityLivingBase)entityHitting;
int hitTime = 5;
if(hitter.getHeldItem() != null)
{
ItemStack attackingWep = hitter.getHeldItem();
if(attackingWep.getItem() instanceof IWeaponSpeed)
{
hitTime += ((IWeaponSpeed)attackingWep.getItem()).modifyHitTime(hitter, weapon);
}
}
if(hitTime > 0)
{
MFLogUtil.logDebug("Recoil hitter: " + hitter.getCommandSenderName() + " for " + hitTime*3 + " ticks.");
EventManagerMF.setHitTime(hitter, hitTime * 3);
}
}
}
}
}
if(StaminaBar.isSystemActive && StaminaBar.doesAffectEntity(user) && !StaminaBar.isAnyStamina(user, false))
{
dam *= Math.max(1.0F, ConfigStamina.exhaustDamage);
}
//Fire dura degrade
if(properHit && source.isFireDamage() && dam > 0)
{
for(int a = 0; a < 4; a++)
{
ItemStack armour = user.getEquipmentInSlot(a+1);
if(armour != null)
{
int dura = (int)(dam)+1;
if(!user.worldObj.isRemote && !isArmourFireImmune(armour, source))
{
MFLogUtil.logDebug("Armour Flame Damage: " + dura);
if(armour.getItemDamage() + dura < armour.getMaxDamage())
{
armour.damageItem(dura, user);
}
else
{
armour.setItemDamage(armour.getMaxDamage());
}
}
if(armour.getItemDamage() >= armour.getMaxDamage())
{
user.setCurrentItemOrArmor(a+1, null);
user.worldObj.playSoundEffect(user.posX, user.posY+user.getEyeHeight() - (0.4F*a), user.posZ, "random.break", 1.0F, 1.0F);
}
}
}
}
if(!source.isUnblockable() && (properHit || source.isProjectile()) && dam > 0 && ArmourCalculator.useThresholdSystem)//THRESHOLD SYSTEM
{
float AC = ArmourCalculator.getACThreshold(user, source);
if(source.isFireDamage())
{
AC *= 0.5F;
}
if(AC > 0)
{
if(dam > 0)
{
for(int a = 0; a < 4; a++)
{
ItemStack armour = user.getEquipmentInSlot(a+1);
if(armour != null)
{
int dura = ArmourCalculator.getDamageToDura(user, source, armour, dam);
if(!user.worldObj.isRemote)
{
if(armour.getItemDamage() + dura < armour.getMaxDamage())
{
armour.damageItem(dura, user);
}
else
{
armour.setItemDamage(armour.getMaxDamage());
}
}
if(armour.getItemDamage() >= armour.getMaxDamage())
{
user.setCurrentItemOrArmor(a+1, null);
user.worldObj.playSoundEffect(user.posX, user.posY+user.getEyeHeight() - (0.4F*a), user.posZ, "random.break", 1.0F, 1.0F);
}
}
}
}
MFLogUtil.logDebug("Init AC Reduction: " + AC);
dam -= AC;
if(dam < 0)dam = 0;
}
}
if(dam > 0 && user instanceof EntityPlayer || (entityHitting != null && entityHitting instanceof EntityPlayer))
{
if(!user.worldObj.isRemote)
{
String type = "Mixed";
float[] f = ArmourCalculator.getRatioForSource(source);
if(f == null)
{
type = "Basic";
}
else
{
if(f[0] > f[1] && f[0] > f[2])type = "Cutting";
if(f[2] > f[1] && f[2] > f[0])type = "Piercing";
if(f[1] > f[0] && f[1] > f[2])type = "Blunt";
}
MFLogUtil.logDebug(dam + "x "+ type +" Damage inflicted to: " + user.getCommandSenderName() + " (" + user.getEntityId() + ")");
}
}
return dam;
}
private boolean isArmourFireImmune(ItemStack armour, DamageSource src)
{
if(armour != null && armour.getItem() instanceof IElementalResistance)
{
return ((IElementalResistance)armour.getItem()).getFireResistance(armour, src) >= 100F;
}
return false;
}
private String getDefaultParrySound(ItemStack weapon)
{
if(weapon.getUnlocalizedName().contains("wood") || weapon.getUnlocalizedName().contains("Wood") || weapon.getUnlocalizedName().contains("stone") || weapon.getUnlocalizedName().contains("Stone"))
{
return "minefantasy2:weapon.wood_parry";
}
return "mob.zombie.metal";
}
/**
* @return 0 for normal parry and 1 for evade
*/
private int onParry(DamageSource source, EntityLivingBase user, Entity attacker, float dam, float prevDam, IParryable parry)
{
/*
if(RPGElements.isSystemActive && user instanceof EntityPlayer)
{
SkillList.block.addXP((EntityPlayer)user, 10 + (int)prevDam*2);
}
*/
if(RPGElements.isSystemActive && user instanceof EntityPlayer )
{
SkillList.combat.addXP((EntityPlayer)user, (int)(prevDam/3F));
}
if(parry != null)
{
parry.onParry(source, user, attacker, dam);
}
boolean groundBlock = user.onGround;
ItemStack weapon = user.getHeldItem();
//Redirect
if(!user.worldObj.isRemote && !TacticalManager.isRanged(source))
{
if(canEvade(user))
{
float powerMod = attacker.isSprinting() ? 4.0F : 2.5F;
attacker.setSprinting(false);
TacticalManager.lungeEntity(attacker, user, powerMod, 0.0F);
TacticalManager.lungeEntity(user, attacker, 3F, 0.0F);
return 1;
}
}
return 0;
}
/**
* Determines if an evade can be made (jump or normal)
*/
private boolean canEvade(EntityLivingBase user)
{
float stamModifier = 1.0F;
if(user instanceof EntityPlayer)
{
if(!ResearchLogic.hasInfoUnlocked((EntityPlayer)user, "parrypro"))
{
return false;
}
if(!isFightStance(user))
{
return false;
}
}
else
{
if(rand.nextInt(10) != 0)//Mobs can evade
{
return false;
}
}
if(!user.onGround && !tryJumpEvade(user, stamModifier))
{
return false;
}
return tryGroundEvade(user, stamModifier);
}
/**
* If the player can slip past enemies
* Should be any armour but heavy
*/
private boolean tryGroundEvade(EntityLivingBase user, float cost)
{
return ItemWeaponMF.tryPerformAbility(user, evade_cost*cost, true, false);
}
/**
* If the player can jump over enemies in evading
* Only ment for unarmoured/Lightarmour
*/
private boolean tryJumpEvade(EntityLivingBase user, float cost)
{
return ItemWeaponMF.tryPerformAbility(user, jumpEvade_cost*cost, true, false);
}
@SubscribeEvent
public void updateLiving(LivingUpdateEvent event)
{
EntityLivingBase living = event.entityLiving;
tickParryCooldown(living);
tickPostHitCooldown(living);
if(living instanceof EntityLiving)
{
EntityLiving mob = (EntityLiving)living;
ItemStack held = mob.getHeldItem();
{
EntityLivingBase tar = mob.getAttackTarget();
if(tar != null && tar instanceof EntityPlayer && ((EntityPlayer)tar).isBlocking())
{
double dist = mob.getDistanceSqToEntity(tar);
if(tar instanceof EntityZombie && mob.onGround && mob.getRNG().nextInt(10) == 0 && dist > 1D && dist < 4D)
{
mob.motionY = 0.5F;
}
}
}
if(isAxe(held))
{
EntityLivingBase tar = mob.getAttackTarget();
if(tar != null)
{
double dist = mob.getDistanceSqToEntity(tar);
if(mob.onGround && mob.getRNG().nextInt(5) == 0 && dist > 1D && dist < 4.0D)
{
mob.motionY = 0.5F;
}
}
if(mob.getRNG().nextInt(100) == 0 && !mob.isSprinting() && !mob.isChild())
{
mob.setSprinting(true);
}
}
if(isFastblade(held))
{
EntityLivingBase tar = mob.getAttackTarget();
if(tar != null)
{
double dist = mob.getDistanceSqToEntity(tar);
if(mob.onGround && mob.getRNG().nextInt(20) == 0 && dist > 1D && dist < 4.0D)
{
mob.motionY = 0.5F;
}
}
if(mob.getRNG().nextInt(20) == 0 && !mob.isSprinting() && !mob.isChild())
{
mob.setSprinting(true);
}
}
if(living.isBurning() && !living.isImmuneToFire())
{
panic(living, 0.25F, 5);
}
}
}
private boolean isAxe(ItemStack held)
{
return held != null && held.getItem() instanceof ItemWaraxeMF || held != null && held.getItem() instanceof ItemBattleaxeMF;
}
private boolean isFastblade(ItemStack held)
{
return held != null && held.getItem() instanceof ItemDagger || held != null && held.getItem() instanceof ItemKatanaMF;
}
private void applyBalance(EntityPlayer entityPlayer)
{
MFLogUtil.logDebug("Weapon Balance Init");
ItemStack weapon = entityPlayer.getHeldItem();
float balance = 0.0F;
if(weapon != null && weapon.getItem() instanceof IWeightedWeapon)
{
balance = ((IWeightedWeapon)weapon.getItem()).getBalance(entityPlayer);
}
if (ConfigWeapon.useBalance && balance > 0 && entityPlayer != null)
{
TacticalManager.throwPlayerOffBalance(entityPlayer, balance, true);
}
}
public static void setParryCooldown(EntityLivingBase user, int ticks)
{
user.getEntityData().setInteger(parryCooldownNBT, ticks);
if(!user.worldObj.isRemote && user instanceof EntityPlayer)
{
EntityPlayer player = (EntityPlayer)user;
((WorldServer)player.worldObj).getEntityTracker().func_151248_b(player, new ParryPacket(ticks, player).generatePacket());
}
}
public static int getParryCooldown(EntityLivingBase user)
{
if(user.getEntityData().hasKey(parryCooldownNBT))
{
return user.getEntityData().getInteger(parryCooldownNBT);
}
return 0;
}
public static void tickParryCooldown(EntityLivingBase user)
{
int ticks = getParryCooldown(user);
if(ticks > 0)
{
setParryCooldown(user, ticks-1);
}
}
public static boolean isParryAvailable(EntityLivingBase user)
{
return getParryCooldown(user)<= 0;
}
public static void setPostHitCooldown(EntityLivingBase user, int ticks)
{
user.getEntityData().setInteger(posthitCooldownNBT, ticks);
}
public static int getPostHitCooldown(EntityLivingBase user)
{
if(user.getEntityData().hasKey(posthitCooldownNBT))
{
return user.getEntityData().getInteger(posthitCooldownNBT);
}
return 0;
}
public static void tickPostHitCooldown(EntityLivingBase user)
{
int ticks = getPostHitCooldown(user);
if(ticks > 0)
{
setPostHitCooldown(user, ticks-1);
}
}
@SubscribeEvent
public void jump(LivingJumpEvent event)
{
if(event.entityLiving instanceof EntityPlayer)
{
if(StaminaBar.isSystemActive && StaminaBar.doesAffectEntity(event.entityLiving))
{
StaminaMechanics.onJump(event.entityLiving);
}
}
}
/*
* Causes the victim to 'Spaz out' which never stops being funny (Apply every tick)
*/
public static void panic(EntityLivingBase victim, float speed, int directionTimer)
{
double moveX = victim.getEntityData().getDouble("MF2_PanicX");
double moveZ = victim.getEntityData().getDouble("MF2_PanicZ");
victim.setJumping(true);
if((moveX == 0 && moveZ == 0) || rand.nextInt(directionTimer) == 0)
{
moveX = (rand.nextDouble()-0.5D)*0.85D * speed;
moveZ = (rand.nextDouble()-0.5D)*0.85D * speed;
victim.getEntityData().setDouble("MF2_PanicX", moveX);
victim.getEntityData().setDouble("MF2_PanicZ", moveZ);
if(victim.onGround)victim.motionY = 0.25F;
victim.rotationYaw = (float)(Math.atan2(moveX, moveZ));
}
victim.swingItem();
victim.limbSwing = 1.0F;
victim.moveEntity(moveX, 0D, moveZ);
}
private float modifyPlayerDamage(EntityPlayer hit, float dam)
{
if(ResearchLogic.hasInfoUnlocked(hit, KnowledgeListMF.toughness))
{
dam *= 0.75F;//25% Resist
}
return dam;
}
/**
* How much strength is added (directly adds to melee dmg)
*/
public static float getStrengthEnhancement(EntityLivingBase user)
{
float dam = 0F;
if(CogworkArmour.hasPoweredSuit(user))
{
dam += 3F;
}
return Math.max(-0.5F, dam);
}
}