package engine.objects; import engine.Enum; import engine.gameManager.ChatManager; import engine.powers.EffectsBase; import engine.powers.effectmodifiers.AbstractEffectModifier; import engine.server.MBServerStatics; import org.pmw.tinylog.Logger; import javax.swing.*; import java.util.ArrayList; import java.util.HashMap; import java.util.concurrent.ConcurrentHashMap; public class PlayerCombatStats { public PlayerCharacter owner; //main hand data public int minDamageHandOne; public int maxDamageHandOne; public float attackSpeedHandOne; public float rangeHandOne; public float atrHandOne; //off hand data public int minDamageHandTwo; public int maxDamageHandTwo; public float attackSpeedHandTwo; public float rangeHandTwo; public float atrHandTwo; //defense public int defense; //regen rates public float healthRegen; public float manaRegen; public float staminaRegen; public PlayerCombatStats(PlayerCharacter pc) { this.owner = pc; this.update(); } public void update() { try { this.calculateATR(true); this.owner.atrHandOne = (int) this.atrHandOne; } catch (Exception e) { //Logger.error("FAILED TO CALCULATE ATR FOR: " + this.owner.getObjectUUID()); } try { this.calculateATR(false); this.owner.atrHandTwo = (int) this.atrHandTwo; } catch (Exception e) { //Logger.error("FAILED TO CALCULATE ATR FOR: " + this.owner.getObjectUUID()); } try { this.calculateMin(true); this.owner.minDamageHandOne = this.minDamageHandOne; } catch (Exception e) { //Logger.error("FAILED TO CALCULATE Min FOR: " + this.owner.getObjectUUID()); } try { this.calculateMin(false); this.owner.minDamageHandTwo = this.minDamageHandTwo; } catch (Exception e) { //Logger.error("FAILED TO CALCULATE Min FOR: " + this.owner.getObjectUUID()); } try { this.calculateMax(true); this.owner.maxDamageHandOne = this.maxDamageHandOne; } catch (Exception e) { //Logger.error("FAILED TO CALCULATE Max FOR: " + this.owner.getObjectUUID()); } try { this.calculateMax(false); this.owner.maxDamageHandTwo = this.maxDamageHandTwo; } catch (Exception e) { //Logger.error("FAILED TO CALCULATE Max FOR: " + this.owner.getObjectUUID()); } try { this.calculateAttackSpeed(true); this.owner.speedHandOne = this.attackSpeedHandOne; } catch (Exception e) { //Logger.error("FAILED TO CALCULATE Attack Speed FOR: " + this.owner.getObjectUUID()); } try { this.calculateAttackSpeed(false); this.owner.speedHandTwo = this.attackSpeedHandTwo; } catch (Exception e) { //Logger.error("FAILED TO CALCULATE Attack Speed FOR: " + this.owner.getObjectUUID()); } try { this.calculateAttackRange(true); this.owner.rangeHandOne = this.rangeHandOne; } catch (Exception e) { //Logger.error("FAILED TO CALCULATE Attack Range FOR: " + this.owner.getObjectUUID()); } try { this.calculateAttackRange(false); this.owner.rangeHandTwo = this.rangeHandTwo; } catch (Exception e) { //Logger.error("FAILED TO CALCULATE Attack Range FOR: " + this.owner.getObjectUUID()); } try { this.calculateDefense(); this.owner.defenseRating = this.defense; } catch (Exception e) { //Logger.error("FAILED TO CALCULATE Defense FOR: " + this.owner.getObjectUUID()); } } public void calculateATR(boolean mainHand) { Item weapon; float atr; if(mainHand) { weapon = this.owner.charItemManager.getEquipped(1); }else { weapon = this.owner.charItemManager.getEquipped(2); } String skill = "Unarmed Combat"; String mastery = "Unarmed Combat Mastery"; int primaryStat = this.owner.statDexCurrent; if(weapon != null) { skill= weapon.getItemBase().getSkillRequired(); mastery = weapon.getItemBase().getMastery(); if(weapon.getItemBase().isStrBased()) primaryStat = this.owner.statStrCurrent; } if(weapon == null) primaryStat = this.owner.statStrCurrent; float skillLevel = 0; float masteryLevel = 0; if(this.owner.skills.containsKey(skill)) { skillLevel = this.owner.skills.get(skill).getModifiedAmount();//calculateBuffedSkillLevel(skill,this.owner);//this.owner.skills.get(skill).getTotalSkillPercet(); } if(this.owner.skills.containsKey(mastery)) masteryLevel = this.owner.skills.get(mastery).getModifiedAmount();//calculateBuffedSkillLevel(mastery,this.owner);//this.owner.skills.get(mastery).getTotalSkillPercet(); float stanceValue = 0.0f; float atrEnchants = 0; for(String effID : this.owner.effects.keySet()) { if (effID.contains("Stance")) { Effect effect = this.owner.effects.get(effID); EffectsBase eb = effect.getEffectsBase(); if(eb.getIDString().equals("STC-H-DA")) continue; for (AbstractEffectModifier mod : this.owner.effects.get(effID).getEffectModifiers()) { if (mod.modType.equals(Enum.ModType.OCV)) { float percent = mod.getPercentMod(); int trains = this.owner.effects.get(effID).getTrains(); float modValue = percent + (trains * mod.getRamp()); stanceValue += modValue * 0.01f; } } } else { for (AbstractEffectModifier mod : this.owner.effects.get(effID).getEffectModifiers()) { if (mod.modType.equals(Enum.ModType.OCV)) { if(mod.getPercentMod() == 0) { float value = mod.getMinMod(); int trains = this.owner.effects.get(effID).getTrains(); float modValue = value + (trains * mod.getRamp()); atrEnchants += modValue; } } } } } float prefixValues = 0.0f; if(weapon != null){ if(this.owner.charItemManager.getEquipped(1) != null){ for(Effect eff : this.owner.charItemManager.getEquipped(1).effects.values()){ for(AbstractEffectModifier mod : eff.getEffectModifiers()){ if(mod.modType.equals(Enum.ModType.OCV)){ prefixValues += mod.minMod + (eff.getTrains() * mod.getRamp()); } } } } } if(this.owner.charItemManager.getEquipped(2) != null){ for(Effect eff : this.owner.charItemManager.getEquipped(2).effects.values()){ for(AbstractEffectModifier mod : eff.getEffectModifiers()){ if(mod.modType.equals(Enum.ModType.OCV)){ prefixValues += mod.minMod + (eff.getTrains() * mod.getRamp()); } } } } float preciseRune = 1.0f; for(CharacterRune rune : this.owner.runes){ if(rune.getRuneBase().getName().equals("Precise")) preciseRune += 0.05f; } atr = primaryStat / 2; atr += skillLevel * 4; atr += masteryLevel * 3; atr += prefixValues; atr *= preciseRune; atr += atrEnchants; atr *= 1.0f + stanceValue; if(this.owner.bonuses != null) { float positivePercentBonuses = this.owner.bonuses.getFloatPercentPositive(Enum.ModType.OCV, Enum.SourceType.None); float negativePercentBonuses = this.owner.bonuses.getFloatPercentNegative(Enum.ModType.OCV, Enum.SourceType.None); float modifier = 1 + (positivePercentBonuses + negativePercentBonuses); if(preciseRune > 1.0f) modifier -= 0.05f; if(stanceValue > 1.0f){ modifier -= (stanceValue - 1.0f); } atr *= modifier; } atr = (float) Math.round(atr); if(mainHand){ this.atrHandOne = atr; }else{ this.atrHandTwo = atr; if(this.owner.charItemManager.getEquipped(1) == null && this.owner.charItemManager.getEquipped(2) != null){ if(!this.owner.charItemManager.getEquipped(2).getItemBase().isShield()) this.atrHandOne = 0.0f; }else if(this.owner.charItemManager.getEquipped(2) == null && this.owner.charItemManager.getEquipped(1) != null){ this.atrHandTwo = 0.0f; } } } //PERFECT DO NOT TOUCH public void calculateMin(boolean mainHand) { Item weapon; float specialDex = this.owner.statDexBase; specialDex += this.owner.bonuses.getFloat(Enum.ModType.Attr, Enum.SourceType.Dexterity); float baseDMG = 1; float primaryStat = specialDex;//getDexAfterPenalty(this.owner); float secondaryStat = this.owner.statStrCurrent; double weaponSkill = 5; double weaponMastery = 5; if (mainHand) { weapon = this.owner.charItemManager.getEquipped(1); } else { weapon = this.owner.charItemManager.getEquipped(2); } String skill = "Unarmed Combat"; String mastery = "Unarmed Combat Mastery"; if (weapon != null) { baseDMG = weapon.getItemBase().getMinDamage(); skill = weapon.getItemBase().getSkillRequired(); mastery = weapon.getItemBase().getMastery(); if (weapon.getItemBase().isStrBased()) { primaryStat = this.owner.statStrCurrent; secondaryStat = specialDex;//getDexAfterPenalty(this.owner); } for(Effect eff : weapon.effects.values()){ for(AbstractEffectModifier mod : eff.getEffectModifiers()){ if(mod.modType.equals(Enum.ModType.MinDamage)){ baseDMG += mod.minMod + (mod.getRamp() * eff.getTrains()); } } } } if (this.owner.skills.containsKey(skill)) { weaponSkill = this.owner.skills.get(skill).getModifiedAmount(); } if (this.owner.skills.containsKey(mastery)) { weaponMastery = this.owner.skills.get(weaponMastery).getModifiedAmount(); } double minDMG = baseDMG * ( 0.0048 * primaryStat + 0.049 * Math.sqrt(primaryStat - 0.75) + 0.0066 * secondaryStat + 0.064 * Math.sqrt(secondaryStat - 0.75) + 0.01 * (weaponSkill + weaponMastery) ); if(this.owner.bonuses != null){ minDMG += this.owner.bonuses.getFloat(Enum.ModType.MinDamage, Enum.SourceType.None); minDMG *= 1 + this.owner.bonuses.getFloatPercentAll(Enum.ModType.MeleeDamageModifier, Enum.SourceType.None); } if(this.owner.charItemManager != null){ if(this.owner.charItemManager.getEquipped(1) != null && this.owner.charItemManager.getEquipped(2) != null && !this.owner.charItemManager.getEquipped(2).getItemBase().isShield()){ minDMG *= 0.7f; } } int roundedMin = (int)Math.round(minDMG); if (mainHand) { this.minDamageHandOne = roundedMin; } else { this.minDamageHandTwo = roundedMin; if(this.owner.charItemManager.getEquipped(1) == null && this.owner.charItemManager.getEquipped(2) != null){ if(!this.owner.charItemManager.getEquipped(2).getItemBase().isShield()) this.minDamageHandOne = 0; }else if(this.owner.charItemManager.getEquipped(2) == null && this.owner.charItemManager.getEquipped(1) != null){ this.minDamageHandTwo = 0; } } } public void calculateMax(boolean mainHand) { Item weapon; double baseDMG = 5; float primaryStat = this.owner.statDexCurrent; float secondaryStat = this.owner.statStrCurrent; double weaponSkill = 5; double weaponMastery = 5; if (mainHand) { weapon = this.owner.charItemManager.getEquipped(1); } else { weapon = this.owner.charItemManager.getEquipped(2); } int extraDamage = 0; String skill = "Unarmed Combat"; String mastery = "Unarmed Combat Mastery"; if (weapon != null) { baseDMG = weapon.getItemBase().getMaxDamage(); skill = weapon.getItemBase().getSkillRequired(); mastery = weapon.getItemBase().getMastery(); if (weapon.getItemBase().isStrBased()) { primaryStat = this.owner.statStrCurrent; secondaryStat = this.owner.statDexCurrent; extraDamage = 3; } for(Effect eff : weapon.effects.values()){ for(AbstractEffectModifier mod : eff.getEffectModifiers()){ if(mod.modType.equals(Enum.ModType.MaxDamage)){ baseDMG += mod.minMod + (mod.getRamp() * eff.getTrains()); } } } } if (this.owner.skills.containsKey(skill)) { weaponSkill = this.owner.skills.get(skill).getModifiedAmount(); } if (this.owner.skills.containsKey(mastery)) { weaponMastery = this.owner.skills.get(mastery).getModifiedAmount(); } double maxDMG = baseDMG * ( 0.0124 * primaryStat + 0.118 * Math.sqrt(primaryStat - 0.75) + 0.0022 * secondaryStat + 0.028 * Math.sqrt(secondaryStat - 0.75) + 0.0075 * (weaponSkill + weaponMastery) ); if(this.owner.bonuses != null){ maxDMG += this.owner.bonuses.getFloat(Enum.ModType.MaxDamage, Enum.SourceType.None); maxDMG *= 1 + this.owner.bonuses.getFloatPercentAll(Enum.ModType.MeleeDamageModifier, Enum.SourceType.None); } if(this.owner.charItemManager != null){ if(this.owner.charItemManager.getEquipped(1) != null && this.owner.charItemManager.getEquipped(2) != null && !this.owner.charItemManager.getEquipped(2).getItemBase().isShield()){ maxDMG *= 0.7f; } } int roundedMax = (int) (Math.round(maxDMG) + extraDamage); if(mainHand){ this.maxDamageHandOne = roundedMax; }else{ this.maxDamageHandTwo = roundedMax; if(this.owner.charItemManager.getEquipped(1) == null && this.owner.charItemManager.getEquipped(2) != null){ if(!this.owner.charItemManager.getEquipped(2).getItemBase().isShield()) this.maxDamageHandOne = 0; }else if(this.owner.charItemManager.getEquipped(2) == null && this.owner.charItemManager.getEquipped(1) != null){ this.maxDamageHandTwo = 0; } } } public void calculateAttackSpeed(boolean mainHand){ Item weapon; float speed; if(mainHand) { weapon = this.owner.charItemManager.getEquipped(1); }else { weapon = this.owner.charItemManager.getEquipped(2); } float delayExtra = 0; if(weapon == null) { speed = 20.0f; }else{ speed = weapon.getItemBase().getSpeed(); for(Effect eff : weapon.effects.values()){ for(AbstractEffectModifier mod : eff.getEffectModifiers()){ if(mod.modType.equals(Enum.ModType.WeaponSpeed) || mod.modType.equals(Enum.ModType.AttackDelay)){ float percent = mod.getPercentMod(); int trains = eff.getTrains(); float modValue = percent + (trains * mod.getRamp()); speed *= 1 + (modValue * 0.01f); } } } } if(this.owner.charItemManager.getEquipped(1) != null){ for(Effect eff : this.owner.charItemManager.getEquipped(1).effects.values()){ for(AbstractEffectModifier mod : eff.getEffectModifiers()){ if(mod.modType.equals(Enum.ModType.AttackDelay)){ float percent = mod.getPercentMod(); int trains = eff.getTrains(); float modValue = percent + (trains * mod.getRamp()); delayExtra += modValue * 0.01f; } } } } if(this.owner.charItemManager.getEquipped(2) != null){ for(Effect eff : this.owner.charItemManager.getEquipped(2).effects.values()){ for(AbstractEffectModifier mod : eff.getEffectModifiers()){ if(mod.modType.equals(Enum.ModType.AttackDelay)){ float percent = mod.getPercentMod(); int trains = eff.getTrains(); float modValue = percent + (trains * mod.getRamp()); delayExtra += modValue * 0.01f; } } } } float stanceValue = 0.0f; for(String effID : this.owner.effects.keySet()){ if(effID.contains("Stance")){ if(this.owner.effects != null) { for (AbstractEffectModifier mod : this.owner.effects.get(effID).getEffectModifiers()) { if (mod.modType.equals(Enum.ModType.AttackDelay)) { float percent = mod.getPercentMod(); int trains = this.owner.effects.get(effID).getTrains(); float modValue = percent + (trains * mod.getRamp()); stanceValue += modValue * 0.01f; } } } } } float bonusValues = 1 + this.owner.bonuses.getFloatPercentAll(Enum.ModType.AttackDelay,Enum.SourceType.None);//1.0f; bonusValues -= stanceValue + delayExtra; // take away stance modifier from alac bonus values speed *= 1 + stanceValue; // apply stance bonus speed *= bonusValues; // apply alac bonuses without stance mod if(speed < 10.0f) speed = 10.0f; if(mainHand){ this.attackSpeedHandOne = speed; }else{ this.attackSpeedHandTwo = speed; if(this.owner.charItemManager.getEquipped(1) == null && this.owner.charItemManager.getEquipped(2) != null){ if(!this.owner.charItemManager.getEquipped(2).getItemBase().isShield()) this.attackSpeedHandOne = 0.0f; }else if(this.owner.charItemManager.getEquipped(2) == null && this.owner.charItemManager.getEquipped(1) != null){ this.attackSpeedHandTwo = 0.0f; } } } public void calculateAttackRange(boolean mainHand){ Item weapon; float range; if(mainHand) { weapon = this.owner.charItemManager.getEquipped(1); }else { weapon = this.owner.charItemManager.getEquipped(2); } if(weapon == null) { range = 6.0f; }else{ range = weapon.getItemBase().getRange(); } if(owner.bonuses != null){ range *= 1 + this.owner.bonuses.getFloatPercentAll(Enum.ModType.WeaponRange, Enum.SourceType.None); } if(mainHand){ this.rangeHandOne = range; }else{ this.rangeHandTwo = range; if(this.owner.charItemManager.getEquipped(1) == null && this.owner.charItemManager.getEquipped(2) != null){ if(!this.owner.charItemManager.getEquipped(2).getItemBase().isShield()) this.rangeHandOne = 0.0f; }else if(this.owner.charItemManager.getEquipped(2) == null && this.owner.charItemManager.getEquipped(1) != null){ this.rangeHandTwo = 0.0f; } } } public void calculateDefense() { //Defense = (1+Armor skill / 50) * Armor defense + (1 + Block skill / 100) * Shield defense + (Primary weapon skill / 2) // + (Weapon mastery skill/ 2) + Dexterity * 2 + Flat bonuses from rings or cloth float armorSkill = 0.0f; float armorDefense = 0.0f; ArrayList armorsUsed = new ArrayList<>(); for(Item equipped : this.owner.charItemManager.getEquipped().values()){ ItemBase ib = equipped.getItemBase(); if(ib.isHeavyArmor() || ib.isMediumArmor() || ib.isLightArmor() || ib.isClothArmor()){ armorDefense += ib.getDefense(); for(Effect eff : equipped.effects.values()){ for(AbstractEffectModifier mod : eff.getEffectModifiers()){ if(mod.modType.equals(Enum.ModType.DR)){ armorDefense += mod.minMod + (mod.getRamp() * eff.getTrains()); } } } if(!ib.isClothArmor() && !armorsUsed.contains(ib.getSkillRequired())) { armorsUsed.add(ib.getSkillRequired()); } } } for(String armorUsed : armorsUsed){ if(this.owner.skills.containsKey(armorUsed)) { armorSkill += this.owner.skills.get(armorUsed).getModifiedAmount();//calculateBuffedSkillLevel(armorUsed,this.owner); } } if(armorsUsed.size() > 0) armorSkill = armorSkill / armorsUsed.size(); float blockSkill = 0.0f; if(this.owner.skills.containsKey("Block")) blockSkill = this.owner.skills.get("Block").getModifiedAmount(); float shieldDefense = 0.0f; if(this.owner.charItemManager.getEquipped(2) != null && this.owner.charItemManager.getEquipped(2).getItemBase().isShield()){ Item shield = this.owner.charItemManager.getEquipped(2); shieldDefense += shield.getItemBase().getDefense(); for(Effect eff : shield.effects.values()){ for(AbstractEffectModifier mod : eff.getEffectModifiers()){ if(mod.modType.equals(Enum.ModType.DR)){ shieldDefense += mod.minMod + (mod.getRamp() * eff.getTrains()); } } } } float weaponSkill = 0.0f; float masterySkill = 0.0f; Item weapon = this.owner.charItemManager.getEquipped(1); if(weapon == null){ weapon = this.owner.charItemManager.getEquipped(2); } if(weapon != null && weapon.getItemBase().isShield()) weapon = null; String skillName = "Unarmed Combat"; String masteryName = "Unarmed Combat Mastery"; if(weapon != null){ skillName = weapon.getItemBase().getSkillRequired(); masteryName = weapon.getItemBase().getMastery(); } if(this.owner.skills.containsKey(skillName)) weaponSkill = this.owner.skills.get(skillName).getModifiedAmount();//calculateBuffedSkillLevel(skillName,this.owner);//this.owner.skills.get(skillName).getModifiedAmount();//calculateModifiedSkill(skillName,this.owner);//this.owner.skills.get(skillName).getModifiedAmount(); if(this.owner.skills.containsKey(masteryName)) masterySkill = this.owner.skills.get(masteryName).getModifiedAmount();//calculateBuffedSkillLevel(masteryName,this.owner);//this.owner.skills.get(masteryName).getModifiedAmount();//calculateModifiedSkill(masteryName,this.owner);//this.owner.skills.get(masteryName).getModifiedAmount(); float dexterity = this.owner.statDexCurrent;//getDexAfterPenalty(this.owner); float luckyRune = 1.0f; for(CharacterRune rune : this.owner.runes){ if(rune.getRuneBase().getName().equals("Lucky")) { luckyRune += 0.05f; break; } } float flatBonuses = 0.0f; float stanceMod = 1.0f; for(String effID : this.owner.effects.keySet()) { if (effID.contains("Stance")) { for (AbstractEffectModifier mod : this.owner.effects.get(effID).getEffectModifiers()) { if (mod.modType.equals(Enum.ModType.DCV)) { float percent = mod.getPercentMod(); int trains = this.owner.effects.get(effID).getTrains(); float modValue = percent + (trains * mod.getRamp()); stanceMod += modValue * 0.01f; } } } else { for (AbstractEffectModifier mod : this.owner.effects.get(effID).getEffectModifiers()) { if (mod.modType.equals(Enum.ModType.DCV)) { if(mod.getPercentMod() == 0) { float value = mod.getMinMod(); int trains = this.owner.effects.get(effID).getTrains(); float modValue = value + (trains * mod.getRamp()); flatBonuses += modValue; } } } } } if(this.owner.charItemManager.getEquipped(2) == null) blockSkill = 0; else if(this.owner.charItemManager != null && this.owner.charItemManager.getEquipped(2) != null && !this.owner.charItemManager.getEquipped(2).getItemBase().isShield()) blockSkill = 0; float defense = (1 + armorSkill / 50) * armorDefense; defense += (1 + blockSkill / 100) * shieldDefense; defense += (weaponSkill / 2); defense += (masterySkill / 2); defense += dexterity * 2; defense += flatBonuses; defense *= luckyRune; defense *= stanceMod; if(this.owner.bonuses != null) { float positivePercentBonuses = this.owner.bonuses.getFloatPercentPositive(Enum.ModType.DCV, Enum.SourceType.None); float negativePercentBonuses = this.owner.bonuses.getFloatPercentNegative(Enum.ModType.DCV, Enum.SourceType.None); float modifier = 1 + (positivePercentBonuses + negativePercentBonuses - (luckyRune - 1.0f) - (stanceMod - 1.0f)); defense *= modifier; } defense = Math.round(defense); this.defense = (int) defense; } // PERFECT DO NOT TOUCH }