/******************************************************************************* * Copyright (c) 2014, 2015 Scott Clarke (scott@dawg6.com). * * This file is part of Dawg6's Demon Hunter DPS Calculator. * * Dawg6's Demon Hunter DPS Calculator is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Dawg6's Demon Hunter DPS Calculator is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. *******************************************************************************/ package com.dawg6.web.dhcalc.shared.calculator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeMap; import java.util.TreeSet; import java.util.Vector; import com.dawg6.d3api.shared.ActiveSkillData; import com.dawg6.d3api.shared.Const; import com.dawg6.d3api.shared.Follower; import com.dawg6.d3api.shared.HeroProfile; import com.dawg6.d3api.shared.ItemInformation; import com.dawg6.d3api.shared.ItemInformationAttribute; import com.dawg6.d3api.shared.ItemInformationGem; import com.dawg6.d3api.shared.ItemInformationSet; import com.dawg6.d3api.shared.LegendaryPowers; import com.dawg6.d3api.shared.PassiveSkill; import com.dawg6.d3api.shared.Value; public class ProfileHelper { public static CharacterData importHero(HeroProfile hero, Integer paragonDexterity) { CharacterData data = new CharacterData(); data.setHeroName(hero.name); data.setParagon(hero.paragonLevel); data.setSeasonal(hero.seasonal); data.setHardcore(hero.hardcore); data.setDead(hero.dead); data.setLevel(hero.level); setHeroSkills(hero, data); setElementalDamage(hero, data); setSkillDamage(hero, data); setGemDamage(hero, data); setFollowerData(hero, data); importWeaponData(hero, data, paragonDexterity); data.setDefaults(); updateCdr(data); data.setDefaults(); return data; } private static void setFollowerData(HeroProfile hero, CharacterData data) { boolean followerOculus = false; double followerOculusPercent = 0.0; if (hero.followers != null) { Follower[] flist = { hero.followers.templar, hero.followers.enchantress, hero.followers.scoundrel }; for (Follower f : flist) { if ((f != null) && (f.items != null)) { ItemInformation[] ilist = { f.items.leftFinger, f.items.rightFinger }; for (ItemInformation i : ilist) { if ((i != null) && (i.name != null)) { if (!followerOculus && i.name.equals(Const.OCULUS_RING)) { followerOculus = true; Value<Float> v = i.attributesRaw.get(Const.OCULUS_RING_PERCENT); if (v != null) { followerOculusPercent = v.min; } else { followerOculusPercent = 0.7; } } } } } } } data.setFollowerOculus(followerOculus); data.setFollowerOculusPercent(followerOculusPercent); } public static void updateCdr(CharacterData data) { List<Double> list = new Vector<Double>(); list.add(data.getParagonCDR() * .002); if (data.isGogok() && data.getGogokLevel() >= 25) list.add(data.getGogokStacks() * .01); GemLevel gem = data.getDiamond(); if (gem != null) { if (data.isLeorics()) { list.add(gem.getCdr() * (1 + (data.getLeoricsPercent() / 100.0))); } else { list.add(gem.getCdr()); } } for (Integer i : data.getCdrData().values()) { if (i != null) list.add(i / 100.0); } if (data.isCrimsonCdr()) list.add(0.10); if (data.isBornsCdr()) list.add(0.10); double effCdr = 0.0; boolean first = true; for (Double c : list) { if (first) { first = false; effCdr = 1.0 - c; } else { effCdr *= (1.0 - c); } } effCdr = 1.0 - effCdr; data.setCdr(effCdr); } public static void updateWeaponDamage(CharacterData data) { double wpnDamage = data.getWeaponDamagePercent(); double min = (data.getBaseMin() + data.getAddMin()) * (1.0 + wpnDamage); double max = (data.getBaseMax() + data.getAddMax()) * (1.0 + wpnDamage); WeaponType type = data.getWeaponType(); if (type == null) type = WeaponType.Bow; double weaponAps = type.getAps() * (1.0 + data.getWeaponIas()); double weaponDps = Math.round(((min + max) / 2.0) * weaponAps * 10.0) / 10.0; data.setWeaponAps(weaponAps); data.setWeaponDps(weaponDps); WeaponType offHand_type = data.getOffHand_weaponType(); double offHand_wpnDamage = data.getOffHand_weaponDamagePercent(); double offHand_min = (data.getOffHand_baseMin() + data .getOffHand_addMin()) * (1.0 + offHand_wpnDamage); double offHand_max = (data.getOffHand_baseMax() + data .getOffHand_addMax()) * (1.0 + offHand_wpnDamage); double offHand_weaponAps = (offHand_type == null) ? 0.0 : (offHand_type .getAps() * (1.0 + data.getOffHand_weaponIas())); double offHand_weaponDps = (offHand_type == null) ? 0.0 : (Math .round(((offHand_min + offHand_max) / 2.0) * offHand_weaponAps * 10.0) / 10.0); data.setOffHand_weaponAps(offHand_weaponAps); data.setOffHand_weaponDps(offHand_weaponDps); min += data.getJewelryMin(); max += data.getJewelryMax(); offHand_min += data.getJewelryMin(); offHand_max += data.getJewelryMax(); double dex = data.getDexterity(); double pCC = (data.getParagonCC() * 0.1) / 100.0; double pCD = (data.getParagonCHD() * 1.0) / 100.0; double aCC = 0.0; double aDam = 0.0; double aCD = 0.0; double ssCC = 0.0; if (data.isSharpshooter()) { ssCC = 0.04; } if (data.isArchery()) { if (type == WeaponType.HandCrossbow) { aCC += 0.05; } else if (type == WeaponType.Bow) { aDam += 0.08; } else if (type == WeaponType.Crossbow) { aCD += 0.5; } } if (data.isSteadyAim()) { aDam += .2; } double critChance = Math.min(1.0, 0.05 + data.getEquipCritChance() + pCC + aCC + ssCC); double critDamage = data.getEquipCritDamage() + pCD + aCD; double eIas = data.getEquipIas(); double wIas = data.getWeaponIas(); double pIas = data.getParagonIAS() * 0.002; double fIas = data.isFocusedMind() ? 0.03 : 0.0; double bbvIas = (data.isBbv() && (data.getBbvUptime() >= 1.0)) ? 0.2 : 0.0; double lovIas = 0.0; if (data.isValor()) { if (data.getValorActiveUptime() >= 1.0) { lovIas = 0.15; } else if ((data.getValorActiveUptime() + data .getValorPassiveUptime()) >= 1.0) { lovIas = 0.08; } } double retIas = (data.isRetribution() && (data.getRetributionUptime() >= 1.0)) ? 0.1 : 0.0; double stIas = (data.isStretchTime() && (data.getStretchTimeUptime() >= 1.0)) ? 0.1 : 0.0; double gogokIas = data.isGogok() ? (data.getGogokStacks() / 100.0) : 0.0; double painEnhancerIas = (data.isPainEnhancer() && data .getPainEnhancerLevel() >= 25) ? (data.getPainEnhancerStacks() * 0.03) : 0.0; double dwIas = (offHand_type != null) ? 0.15 : 0.0; double aps = type.getAps() * (1.0 + wIas) * (1.0 + eIas + fIas + pIas + gogokIas + painEnhancerIas + dwIas + bbvIas + lovIas + retIas + stIas); double averageWeaponDamage = ((min + max) / 2.0); double offHand_averageWeaponDamage = ((offHand_min + offHand_max) / 2.0); double dps = averageWeaponDamage * aps * (1.0 + critChance * critDamage) * (1.0 + (dex / 100.0)) * (1.0 + aDam); double sheetDps = Math.round(dps * 10.0) / 10.0; data.setSheetDps(sheetDps); data.setAps(aps); // double petIasValue = data.isTnt() ? data.getTntPercent() : 0.0; // double petApsValue = aps * (1.0 + petIasValue) * (1.0 + gogokIas); data.setCritChance(critChance); data.setCritHitDamage(critDamage); data.setWeaponDamage(averageWeaponDamage); data.setOffHand_weaponDamage(offHand_averageWeaponDamage); double offHand_wIas = data.getOffHand_weaponIas(); double offHand_aps = (offHand_type == null) ? 0.0 : (offHand_type.getAps() * (1.0 + offHand_wIas) * (1.0 + eIas + pIas + gogokIas + painEnhancerIas + dwIas + bbvIas + lovIas + retIas + stIas)); data.setOffHand_aps(offHand_aps); double offHand_dps = offHand_averageWeaponDamage * offHand_aps * (1.0 + critChance * critDamage) * (1.0 + (dex / 100.0)) * (1.0 + aDam); double offHand_sheetDps = Math.round(offHand_dps * 10.0) / 10.0; data.setOffHand_dps(offHand_sheetDps); } public static void setHeroSkills(HeroProfile hero, CharacterData data) { Map<ActiveSkill, Rune> skills = new TreeMap<ActiveSkill, Rune>(); if ((hero.skills != null) && (hero.skills.active != null)) { for (ActiveSkillData s : hero.skills.active) { if ((s != null) && (s.skill != null) && (s.skill.slug != null)) { for (ActiveSkill sk : ActiveSkill.values()) { SkillType type = sk.getSkillType(); if (type != SkillType.NA) { if (s.skill.slug.equals(sk.getSlug())) { Rune rune = Rune.None; if ((s.rune != null) && (s.rune.type != null)) { for (Rune r : sk.getRunes()) { if (r.getSlug().equals(s.rune.type)) { rune = r; break; } } } skills.put(sk, rune); } } } } } } Set<Passive> passives = new TreeSet<Passive>(); for (PassiveSkill p : hero.skills.passive) { if ((p != null) && (p.skill != null) && (p.skill.slug != null)) { Passive passive = Passive.fromSlug(p.skill.slug); if (passive != null) passives.add(passive); } } for (ItemInformation item : hero.items.values()) { if ((item != null) && (item.attributes != null) && (item.attributes.passive != null)) { for (ItemInformationAttribute a : item.attributes.passive) { if ((a != null) && (a.text != null) && (a.text.length() > 0)) { if (a.text.startsWith(Const.HELLFIRE_PASSIVE)) { String pname = a.text .substring(Const.HELLFIRE_PASSIVE.length()); pname = pname.substring(0, pname.length() - Const.PASSIVE.length()); Passive passive = Passive.fromName(pname); if (passive != null) { passives.add(passive); } } } } } } data.setPassives(passives); data.setHeroLevel(hero.level); data.setSkills(skills); } public static Rune lookupRune(ActiveSkill skill, String name) { for (Rune r : skill.getRunes()) { if (name.equalsIgnoreCase(r.getLongName())) { return r; } } return Rune.None; } public static void setElementalDamage(HeroProfile hero, CharacterData data) { Map<DamageType, Double> damage = new TreeMap<DamageType, Double>(); for (DamageType t : DamageType.values()) { double d = 0.0; String e = t.getSlug(); String attr = Const.ELEMENTAL_DAMAGE_BONUS + e; for (ItemInformation i : hero.items.values()) { if (i != null) { Value<Float> f = i.attributesRaw.get(attr); if (f != null) { d += f.min; } if (t == DamageType.Fire) { f = i.attributesRaw.get(Const.MAGEFIST_FIRE_DAMAGE); if (f != null) { d += f.min; } } if (t == DamageType.Cold) { f = i.attributesRaw.get(Const.FROSTBURN_COLD_DAMAGE); if (f != null) { d += f.min; } } } } if (t == DamageType.Fire) { if (hero.legendaryPowers != null) { for (LegendaryPowers lp : hero.legendaryPowers) { if ((lp != null) && (lp.name != null)) { if (lp.name.equals(Const.MAGEFIST)) { d += 0.2; } } } } } if (t == DamageType.Cold) { if (hero.legendaryPowers != null) { for (LegendaryPowers lp : hero.legendaryPowers) { if ((lp != null) && (lp.name != null)) { if (lp.name.equals(Const.FROSTBURN)) { d += 0.2; } } } } } if (d > 0.0) { damage.put(t, d); } } data.setElementalDamage(damage); } public static void setGemDamage(HeroProfile hero, CharacterData data) { Map<GemSkill, GemAttributeData> gems = new TreeMap<GemSkill, GemAttributeData>(); for (ItemInformation i : hero.items.values()) { if ((i != null) && (i.gems != null)) { for (ItemInformationGem g : i.gems) { if (g.item.name != null) { GemSkill gem = GemSkill.getGemByName(g.item.name); if (gem != null) { GemAttributeData gd = new GemAttributeData(); gd.level = g.jewelRank; for (GemSkill.Attribute a : gem.getAttributes()) { gd.put(a.getLabel(), new Integer(0)); } gems.put(gem, gd); } } } } } data.setGems(gems); } public static void importWeaponData(HeroProfile hero, CharacterData data, Integer paragonDexterity) { double critChance = 0.0; double critDamage = 0.5; WeaponType type = null; int weaponIas = 0; WeaponType offHand_type = null; int offHand_weaponIas = 0; int equipIas = 0; double wpnDamage = 0.0; double offHand_wpnDamage = 0.0; double minJewelry = 0.0; double maxJewelry = 0.0; double baseMin = 0.0; double baseDelta = 0.0; double addMin = 0.0; double addDelta = 0.0; double offHand_baseMin = 0.0; double offHand_baseDelta = 0.0; double offHand_addMin = 0.0; double offHand_addDelta = 0.0; int equipmentDexterity = 0; double areaDamage = 0.0; int numAncients = 0; ItemInformation mainHand = hero.items.get(Slot.MainHand.getSlot()); if (mainHand != null) { String t = mainHand.type.id; type = WeaponType.fromSlug(t); } data.setWeaponType(type); ItemInformation offHand = hero.items.get(Slot.OffHand.getSlot()); if (offHand != null) { String bowType = offHand.type.id; if (bowType.equalsIgnoreCase(Const.HANDXBOW)) { offHand_type = WeaponType.HandCrossbow; } else if (bowType.equalsIgnoreCase(Const.BOW)) { offHand_type = WeaponType.Bow; } else if (bowType.equalsIgnoreCase(Const.CROSSBOW)) { offHand_type = WeaponType.Crossbow; } else { offHand_type = null; } } data.setOffHand_weaponType(offHand_type); if ((mainHand != null) && (type != null)) { for (Map.Entry<String, Value<Float>> e : mainHand.attributesRaw .entrySet()) { if ((e != null) && (e.getKey() != null) && (e.getValue() != null)) { String name = e.getKey(); double value = e.getValue().min; if (name.startsWith(Const.DAMAGE_WEAPON_MIN)) { if (name.contains(Const.PHYSICAL)) baseMin = value; else addMin += value; } else if (name.startsWith(Const.DAMAGE_WEAPON_DELTA)) { if (name.contains(Const.PHYSICAL)) baseDelta = value; else addDelta += value; } else if (name.startsWith(Const.DAMAGE_WEAPON_BONUS_MIN)) { addMin += value; } else if (name.startsWith(Const.DAMAGE_WEAPON_BONUS_DELTA)) { addDelta += value; } else if (name.startsWith(Const.DAMAGE_WEAPON_PERCENT)) wpnDamage = value; else if (name.equals(Const.WEAPON_IAS)) { weaponIas = (int) Math.round(value * 100.0); } } data.setBaseMin(baseMin); data.setBaseMax(baseMin + baseDelta); data.setAddMin(addMin); data.setAddMax(addMin + addDelta); } } if ((offHand != null) && (offHand_type != null)) { for (Map.Entry<String, Value<Float>> e : offHand.attributesRaw .entrySet()) { if ((e != null) && (e.getKey() != null) && (e.getValue() != null)) { String name = e.getKey(); double value = e.getValue().min; if (name.startsWith(Const.DAMAGE_WEAPON_MIN)) { if (name.contains(Const.PHYSICAL)) offHand_baseMin = value; else offHand_addMin += value; } else if (name.startsWith(Const.DAMAGE_WEAPON_DELTA)) { if (name.contains(Const.PHYSICAL)) offHand_baseDelta = value; else offHand_addDelta += value; } else if (name.startsWith(Const.DAMAGE_WEAPON_BONUS_MIN)) { offHand_addMin += value; } else if (name.startsWith(Const.DAMAGE_WEAPON_BONUS_DELTA)) { offHand_addDelta += value; } else if (name.startsWith(Const.DAMAGE_WEAPON_PERCENT)) offHand_wpnDamage = value; else if (name.equals(Const.WEAPON_IAS)) { offHand_weaponIas = (int) Math.round(value * 100.0); } } data.setOffHand_baseMin(offHand_baseMin); data.setOffHand_baseMax(offHand_baseMin + offHand_baseDelta); data.setOffHand_addMin(offHand_addMin); data.setOffHand_addMax(offHand_addMin + offHand_addDelta); } } // StringBuffer log = new StringBuffer(); for (ItemInformation i : hero.items.values()) { if (i != null) { Value<Float> v = i.attributesRaw.get(Const.CRIT_CHANCE_RAW); if (v != null) { critChance += v.min; } v = i.attributesRaw.get(Const.DEXTERITY); if (v != null) { equipmentDexterity += v.min; } v = i.attributesRaw.get(Const.CUBE_GEM_TYPE); if ((v != null) && (v.min == Const.CUBE_DEXTERITY_GEM_TYPE)) { v = i.attributesRaw.get(Const.CUBE_GEM_RANK); if (v != null) { int l = Math.round(v.min); equipmentDexterity += (l * 5); } } v = i.attributesRaw.get(Const.AREA_DAMAGE); if (v != null) { areaDamage += v.min; } v = i.attributesRaw.get(Const.CRIT_DAMAGE_RAW); if (v != null) { critDamage += v.min; } v = i.attributesRaw.get(Const.ANCIENT); if ((v != null) && (v.min >= 1.0)) { numAncients++; } if (i.gems != null) { for (ItemInformationGem g : i.gems) { v = g.attributesRaw.get(Const.CRIT_DAMAGE_RAW); if (v != null) { critDamage += v.min; } v = g.attributesRaw.get(Const.DEXTERITY); if (v != null) { equipmentDexterity += v.min; } } } if ((i != mainHand) && ((i != offHand) || (offHand_type == null))) { if (i.attributesRaw != null) { Value<Float> min = i.attributesRaw .get(Const.JEWELY_MIN_DAMAGE); if (min != null) { minJewelry += min.min; Value<Float> delta = i.attributesRaw .get(Const.JEWELY_DELTA_DAMAGE); if (delta != null) { maxJewelry += (min.min + delta.min); } } } v = i.attributesRaw.get(Const.IAS); if (v != null) { equipIas += Math.round(v.min * 100.0); } } } } for (Map.Entry<String, Integer> e : data.getSetCounts().entrySet()) { int count = e.getValue(); if ((count > 1) && data.isRoyalRing()) count++; ItemInformationSet set = data.getSets().get(e.getKey()); for (ItemInformationSet.Rank r : set.ranks) { if (r.required <= count) { if (r.attributesRaw != null) { Value<Float> v = r.attributesRaw .get(Const.CRIT_CHANCE_RAW); if (v != null) { critChance += v.min; } v = r.attributesRaw.get(Const.DEXTERITY); if (v != null) { equipmentDexterity += v.min; } v = r.attributesRaw.get(Const.AREA_DAMAGE); if (v != null) { areaDamage += v.min; } v = r.attributesRaw.get(Const.CRIT_DAMAGE_RAW); if (v != null) { critDamage += v.min; } v = r.attributesRaw.get(Const.IAS); if (v != null) { equipIas += (int) Math.round(v.min * 100.0); } } } } } data.setEquipCritChance(critChance); data.setEquipCritDamage(critDamage); data.setWeaponIas(weaponIas / 100.0); data.setOffHand_weaponIas(offHand_weaponIas / 100.0); data.setEquipIas(equipIas / 100.0); data.setWeaponDamagePercent(wpnDamage); data.setOffHand_weaponDamagePercent(offHand_wpnDamage); data.setEquipmentDexterity(equipmentDexterity); data.setNumAncients(numAncients); if (paragonDexterity != null) data.setParagonDexterity(paragonDexterity); else { data.setParagonDexterity((hero.stats.dexterity - (equipmentDexterity + 7 + (hero.level * 3))) / 5); } data.setAreaDamageEquipment(areaDamage); data.setJewelryMin(minJewelry); data.setJewelryMax(maxJewelry); } public static void setSkillDamage(HeroProfile hero, CharacterData data) { Map<ActiveSkill, Double> damage = new TreeMap<ActiveSkill, Double>(); Map<Slot, ItemHolder> items = new TreeMap<Slot, ItemHolder>(); double elite = 0; Map<String, Integer> setCounts = new TreeMap<String, Integer>(); Map<String, ItemInformationSet> sets = new TreeMap<String, ItemInformationSet>(); data.setSets(sets); double hatredPerSecond = 0.0; int discipline = 0; boolean otherSets = false; for (Map.Entry<String, ItemInformation> e : hero.items.entrySet()) { if ((e != null) && (e.getKey() != null) && (e.getValue() != null)) { Slot slot = Slot.getSlot(e.getKey()); ItemInformation i = e.getValue(); if (i != null) { if (i.attributesRaw != null) { Value<Float> v = i.attributesRaw .get(Const.ELITE_DAMAGE_RAW); if (v != null) { elite += v.min; } v = i.attributesRaw.get(Const.HATRED_PER_SECOND); if (v != null) { hatredPerSecond += v.min; } v = i.attributesRaw.get(Const.MAX_DISCIPLINE); if (v != null) { discipline += v.min; } } if ((i.set != null) && (i.set.slug != null)) { Integer count = setCounts.get(i.set.slug); if (count == null) { setCounts.put(i.set.slug, 1); sets.put(i.set.slug, i.set); } else { setCounts.put(i.set.slug, count + 1); } } for (SpecialItemType type : SpecialItemType.values()) { if (i.name.equals(type.getName())) { AttributeData ad = new AttributeData(); for (SpecialItemType.Attribute a : type .getAttributes()) { int value = 0; Value<Float> v = i.attributesRaw.get(a .getSlug()); if (v == null) { value = a.setRawAttributeValue(a.getMin()); } else { value = a.setRawAttributeValue(v.min); } ad.put(a.getLabel(), value); } ItemHolder item = new ItemHolder(); item.setType(type); item.setAttributes(ad); items.put(slot, item); } } } } } if (hero.legendaryPowers != null) { for (LegendaryPowers lp : hero.legendaryPowers) { for (SpecialItemType type : SpecialItemType.values()) { if ((lp != null) && (lp.name != null)) { if (lp.name.equals(type.getName())) { AttributeData ad = new AttributeData(); for (SpecialItemType.Attribute a : type .getAttributes()) { int value = a.setRawAttributeValue(a.getMax()); ad.put(a.getLabel(), value); } ItemHolder item = new ItemHolder(); item.setType(type); item.setAttributes(ad); for (Slot slot : type.getSlots()) { if (slot.isCube()) { items.put(slot, item); break; } } } } } } } data.setSpecialItems(items); for (Map.Entry<String, Integer> e : setCounts.entrySet()) { int count = e.getValue(); if ((count > 1) && data.isRoyalRing()) count++; ItemInformationSet set = sets.get(e.getKey()); boolean found = false; for (ItemSet ss : ItemSet.values()) { if (ss.getSlug().equals(e.getKey())) { found = true; break; } } if ((count > 1) && !found) { otherSets = true; // GWT.log("OtherSets = true because of " + e.getKey()); } // GWT.log("set " + e.getKey() + " count " + count); for (ItemInformationSet.Rank r : set.ranks) { if (r.required <= count) { if (r.attributesRaw != null) { Value<Float> v = r.attributesRaw .get(Const.ELITE_DAMAGE_RAW); if (v != null) { elite += v.min; } } } } } data.setSetCounts(setCounts); data.setOtherSets(otherSets); for (ActiveSkill skill : ActiveSkill.values()) { String slug = skill.getDamageAttribute(); String attr = Const.SKILL_DAMAGE_BONUS + slug; double d = 0.0; for (ItemInformation i : hero.items.values()) { if (i != null) { Value<Float> f = i.attributesRaw.get(attr); if (f != null) { d += f.min; } } } if (d > 0.0) { damage.put(skill, d); } } data.setSkillDamage(damage); ItemInformation helm = hero.items.get(Const.HEAD); GemLevel diamond = GemLevel.None; GemLevel topaz = GemLevel.None; Map<String, Integer> cdrData = new TreeMap<String, Integer>(); addCdr(hero, Const.SHOULDERS, cdrData); addCdr(hero, Const.GLOVES, cdrData); addCdr(hero, Const.RING1, cdrData); addCdr(hero, Const.RING2, cdrData); addCdr(hero, Const.BELT, cdrData); addCdr(hero, Const.WEAPON, cdrData); addCdr(hero, Const.QUIVER, cdrData); addCdr(hero, Const.AMULET, cdrData); Map<String, Integer> rcrData = new TreeMap<String, Integer>(); addRcr(hero, Const.SHOULDERS, rcrData); addRcr(hero, Const.GLOVES, rcrData); addRcr(hero, Const.RING1, rcrData); addRcr(hero, Const.RING2, rcrData); addRcr(hero, Const.BELT, rcrData); addRcr(hero, Const.WEAPON, rcrData); addRcr(hero, Const.QUIVER, rcrData); addRcr(hero, Const.AMULET, rcrData); data.setCdrData(cdrData); data.setRcrData(rcrData); if (helm != null) { if (helm.gems != null) { for (ItemInformationGem gem : helm.gems) { Value<Float> value = gem.attributesRaw.get(Const.CDR); if (value != null) { int a = (int) Math.round(value.min * 10000.0); for (GemLevel l : GemLevel.values()) { int b = (int) Math.round(l.getCdr() * 10000.0); if (a == b) { diamond = l; break; } } } value = gem.attributesRaw.get(Const.RCR); if (value != null) { int a = (int) Math.round(value.min * 10000.0); for (GemLevel l : GemLevel.values()) { int b = (int) Math.round(l.getCdr() * 10000.0); if (a == b) { topaz = l; break; } } } } } } data.setHatredPerSecond(hatredPerSecond); data.setEquipmentDiscipline(discipline); data.setEliteDamage(elite); data.setDiamond(diamond); data.setTopaz(topaz); } public static int getSetCount(CharacterData data, String name) { return data.getSetCount(name); } private static void addCdr(HeroProfile hero, String slot, Map<String, Integer> cdrData) { Integer cdr = 0; ItemInformation i = hero.items.get(slot); if (i != null) { Value<Float> value = i.attributesRaw.get(Const.CDR); if (value != null) { cdr = (int) Math.round(value.min * 100.0); } } cdrData.put(slot, cdr); } private static void addRcr(HeroProfile hero, String slot, Map<String, Integer> rcrData) { Integer rcr = 0; ItemInformation i = hero.items.get(slot); if (i != null) { Value<Float> value = i.attributesRaw.get(Const.RESOURCE_REDUCTION); if (value != null) { rcr = (int) Math.round(value.min * 100.0); } } rcrData.put(slot, rcr); } public static void updateRcr(CharacterData data) { List<Double> list = new Vector<Double>(); list.add(data.getParagonRCR() * 0.002); if (data.isPridesFall()) list.add(0.30); Map<String, Integer> map = data.getRcrData(); for (Integer i : map.values()) { if (i != null) list.add(i / 100.0); } if (data.getSetCount(ItemSet.Crimson.getSlug()) >= 3) list.add(0.10); GemLevel gem = data.getTopaz(); if (gem != null) { if (data.isLeorics()) { list.add(gem.getRcr() * (1 + (data.getLeoricsPercent() / 100.0))); } else { list.add(gem.getRcr()); } } double effRcr = 0.0; boolean first = true; for (Double c : list) { if (first) { first = false; effRcr = 1.0 - c; } else { effRcr *= (1.0 - c); } } effRcr = 1.0 - effRcr; data.setRcr(effRcr); } }