/* * Copyright (C) 2022 NotEnoughUpdates contributors * * This file is part of NotEnoughUpdates. * * NotEnoughUpdates is free software: you can redistribute it * and/or modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation, either * version 3 of the License, or (at your option) any later version. * * NotEnoughUpdates 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with NotEnoughUpdates. If not, see . */ package io.github.moulberry.notenoughupdates.profileviewer; import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonPrimitive; import io.github.moulberry.notenoughupdates.NotEnoughUpdates; import io.github.moulberry.notenoughupdates.miscfeatures.PetInfoOverlay; import io.github.moulberry.notenoughupdates.profileviewer.info.QuiverInfo; import io.github.moulberry.notenoughupdates.util.Constants; import io.github.moulberry.notenoughupdates.util.PetLeveling; import io.github.moulberry.notenoughupdates.util.Utils; import net.minecraft.nbt.CompressedStreamTools; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagList; import net.minecraft.util.EnumChatFormatting; import org.apache.commons.lang3.StringUtils; import org.jetbrains.annotations.Nullable; import java.io.ByteArrayInputStream; import java.io.IOException; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; public class PlayerStats { public static final String HEALTH = "health"; public static final String DEFENCE = "defence"; public static final String STRENGTH = "strength"; public static final String SPEED = "speed"; public static final String CRIT_CHANCE = "crit_chance"; public static final String CRIT_DAMAGE = "crit_damage"; public static final String BONUS_ATTACK_SPEED = "bonus_attack_speed"; public static final String INTELLIGENCE = "intelligence"; public static final String SEA_CREATURE_CHANCE = "sea_creature_chance"; public static final String MAGIC_FIND = "magic_find"; public static final String PET_LUCK = "pet_luck"; public static final String MINING_FORTUNE = "mining_fortune"; public static final String MINING_SPEED = "mining_speed"; public static final String[] defaultStatNames = new String[] { "health", "defence", "strength", "speed", "crit_chance", "crit_damage", "bonus_attack_speed", "intelligence", "sea_creature_chance", "magic_find", "pet_luck", "ferocity", "ability_damage", "mining_fortune", "mining_speed", }; public static final String[] defaultStatNamesPretty = new String[] { EnumChatFormatting.RED + "\u2764 Health", EnumChatFormatting.GREEN + "\u2748 Defence", EnumChatFormatting.RED + "\u2741 Strength", EnumChatFormatting.WHITE + "\u2726 Speed", EnumChatFormatting.BLUE + "\u2623 Crit Chance", EnumChatFormatting.BLUE + "\u2620 Crit Damage", EnumChatFormatting.YELLOW + "\u2694 Attack Speed", EnumChatFormatting.AQUA + "\u270e Intelligence", EnumChatFormatting.DARK_AQUA + "\u03b1 SC Chance", EnumChatFormatting.AQUA + "\u272f Magic Find", EnumChatFormatting.LIGHT_PURPLE + "\u2663 Pet Luck", EnumChatFormatting.RED + "\u2AFD Ferocity", EnumChatFormatting.RED + "\u2739 Ability Damage", EnumChatFormatting.GOLD + "\u2618 Mining Fortune", EnumChatFormatting.GOLD + "\u2E15 Mining Speed", }; private static final HashMap STAT_PATTERN_MAP = new HashMap() { { put(HEALTH, Pattern.compile("^Health: ((?:\\+|-)[0-9]+)")); put(DEFENCE, Pattern.compile("^Defense: ((?:\\+|-)[0-9]+)")); put(STRENGTH, Pattern.compile("^Strength: ((?:\\+|-)[0-9]+)")); put(SPEED, Pattern.compile("^Speed: ((?:\\+|-)[0-9]+)")); put(CRIT_CHANCE, Pattern.compile("^Crit Chance: ((?:\\+|-)[0-9]+)")); put(CRIT_DAMAGE, Pattern.compile("^Crit Damage: ((?:\\+|-)[0-9]+)")); put(BONUS_ATTACK_SPEED, Pattern.compile("^Bonus Attack Speed: ((?:\\+|-)[0-9]+)")); put(INTELLIGENCE, Pattern.compile("^Intelligence: ((?:\\+|-)[0-9]+)")); put(SEA_CREATURE_CHANCE, Pattern.compile("^Sea Creature Chance: ((?:\\+|-)[0-9]+)")); put("ferocity", Pattern.compile("^Ferocity: ((?:\\+|-)[0-9]+)")); put("ability_damage", Pattern.compile("^Ability Damage: ((?:\\+|-)[0-9]+)")); } }; public static Stats getBaseStats() { JsonObject misc = Constants.MISC; if (misc == null) return null; Stats stats = new Stats(); for (String statName : defaultStatNames) { stats.addStat(statName, Utils.getElementAsFloat(Utils.getElement(misc, "base_stats." + statName), 0)); } return stats; } private static Stats getFairyBonus(int fairyExchanges) { Stats bonus = new Stats(); bonus.addStat(SPEED, fairyExchanges / 10); for (int i = 0; i < fairyExchanges; i++) { bonus.addStat(STRENGTH, (i + 1) % 5 == 0 ? 2 : 1); bonus.addStat(DEFENCE, (i + 1) % 5 == 0 ? 2 : 1); bonus.addStat(HEALTH, 3 + i / 2); } return bonus; } private static Stats getSkillBonus(Map skyblockInfo) { JsonObject bonuses = Constants.BONUSES; if (bonuses == null) return null; Stats skillBonus = new Stats(); for (Map.Entry entry : skyblockInfo.entrySet()) { JsonElement element = Utils.getElement(bonuses, "bonus_stats." + entry.getKey()); if (element != null && element.isJsonObject()) { JsonObject skillStatMap = element.getAsJsonObject(); Stats currentBonus = new Stats(); for (int i = 1; i <= entry.getValue().level; i++) { if (skillStatMap.has("" + i)) { currentBonus = new Stats(); for (Map.Entry entry2 : skillStatMap.get("" + i).getAsJsonObject().entrySet()) { currentBonus.addStat(entry2.getKey(), entry2.getValue().getAsFloat()); } } skillBonus.add(currentBonus); } } } return skillBonus; } public static int getPetScore(JsonObject profile) { JsonObject bonuses = Constants.BONUSES; if (bonuses == null) { Utils.showOutdatedRepoNotification("bonuses.json"); return 0; } JsonElement petsElement = Utils.getElement(profile, "pets"); if (petsElement == null) return 0; JsonArray pets = petsElement.getAsJsonArray(); HashMap highestRarityMap = new HashMap<>(); for (int i = 0; i < pets.size(); i++) { JsonObject pet = pets.get(i).getAsJsonObject(); highestRarityMap.put(pet.get("type").getAsString(), pet.get("tier").getAsString()); } int petScore = 0; for (String value : highestRarityMap.values()) { petScore += Utils.getElementAsFloat(Utils.getElement(bonuses, "pet_value." + value.toUpperCase()), 0); } return petScore; } private static Stats getTamingBonus(JsonObject profile) { JsonObject bonuses = Constants.BONUSES; if (bonuses == null) return null; JsonElement petRewardsElement = Utils.getElement(bonuses, "pet_rewards"); if (petRewardsElement == null) return null; JsonObject petRewards = petRewardsElement.getAsJsonObject(); int petScore = getPetScore(profile); Stats petBonus = new Stats(); for (int i = 0; i <= petScore; i++) { if (petRewards.has("" + i)) { petBonus = new Stats(); for (Map.Entry entry : petRewards.get("" + i).getAsJsonObject().entrySet()) { petBonus.addStat(entry.getKey(), entry.getValue().getAsFloat()); } } } return petBonus; } private static float harpBonus(JsonObject profile) { String talk_to_melody = Utils.getElementAsString(Utils.getElement(profile, "objectives.talk_to_melody.status"), "INCOMPLETE"); if (talk_to_melody.equalsIgnoreCase("COMPLETE")) { return 26; } else { return 0; } } private static float hotmFortune(JsonObject profile, Map skyblockInfo) { int miningLevelFortune = (int) (4 * (float) Math.floor(skyblockInfo.get("mining").level)); int miningFortuneStat = ((Utils.getElementAsInt(Utils.getElement(profile, "mining_core.nodes.mining_fortune"), 0)) * 5); int miningFortune2Stat = ((Utils.getElementAsInt(Utils.getElement(profile, "mining_core.nodes.mining_fortune_2"), 0)) * 5); return miningFortuneStat + miningFortune2Stat + miningLevelFortune; } private static float hotmSpeed(JsonObject profile) { int miningSpeedStat = ((Utils.getElementAsInt(Utils.getElement(profile, "mining_core.nodes.mining_speed"), 0)) * 20); int miningSpeed2Stat = ((Utils.getElementAsInt(Utils.getElement(profile, "mining_core.nodes.mining_speed_2"), 0)) * 40); return miningSpeedStat + miningSpeed2Stat; } public static Stats getPassiveBonuses(Map skyblockInfo, JsonObject profile) { Stats passiveBonuses = new Stats(); Stats fairyBonus = getFairyBonus((int) Utils.getElementAsFloat(Utils.getElement(profile, "fairy_soul.fairy_exchanges"), 0)); Stats skillBonus = getSkillBonus(skyblockInfo); Stats petBonus = getTamingBonus(profile); if (skillBonus == null || petBonus == null) { return null; } passiveBonuses.add(fairyBonus); passiveBonuses.add(skillBonus); passiveBonuses.addStat(INTELLIGENCE, harpBonus(profile)); passiveBonuses.add(petBonus); return passiveBonuses; } public static Stats getHOTMBonuses(Map skyblockInfo, JsonObject profile) { Stats hotmBonuses = new Stats(); hotmBonuses.addStat(MINING_FORTUNE, hotmFortune(profile, skyblockInfo)); hotmBonuses.addStat(MINING_SPEED, hotmSpeed(profile)); return hotmBonuses; } private static String getFullset(JsonArray armor, int ignore) { String fullset = null; for (int i = 0; i < armor.size(); i++) { if (i == ignore) continue; JsonElement itemElement = armor.get(i); if (itemElement == null || !itemElement.isJsonObject()) { fullset = null; break; } JsonObject item = itemElement.getAsJsonObject(); String internalname = item.get("internalname").getAsString(); String[] split = internalname.split("_"); split[split.length - 1] = ""; String armorname = StringUtils.join(split, "_"); if (fullset == null) { fullset = armorname; } else if (!fullset.equalsIgnoreCase(armorname)) { fullset = null; break; } } return fullset; } private static Stats getSetBonuses( Stats stats, Map inventoryInfo, Map skyblockInfo, JsonObject profile ) { JsonArray armor = inventoryInfo.get("inv_armor"); Stats bonuses = new Stats(); String fullset = getFullset(armor, -1); if (fullset != null) { // TODO @nea: repo based stat delivery? (with lisp) switch (fullset) { case "LAPIS_ARMOR_": bonuses.addStat(HEALTH, 60); break; case "FAIRY_": bonuses.addStat(HEALTH, Utils.getElementAsFloat(Utils.getElement(profile, "fairy_souls_collected"), 0)); break; case "SPEEDSTER_": bonuses.addStat(SPEED, 20); break; case "YOUNG_DRAGON_": bonuses.addStat(SPEED, 70); break; case "MASTIFF_": bonuses.addStat(HEALTH, 50 * Math.round(stats.get(CRIT_DAMAGE))); break; case "ANGLER_": bonuses.addStat(HEALTH, 10 * (float) Math.floor(skyblockInfo.get("fishing").level)); bonuses.addStat(SEA_CREATURE_CHANCE, 4); break; case "ARMOR_OF_MAGMA_": int bonus = (int) Math.min( 200, Math.floor(Utils.getElementAsFloat(Utils.getElement(profile, "stats.kills_magma_cube"), 0) / 10) ); bonuses.addStat(HEALTH, bonus); bonuses.addStat(INTELLIGENCE, bonus); case "OLD_DRAGON_": bonuses.addStat(HEALTH, 200); bonuses.addStat(DEFENCE, 40); break; } } JsonElement chestplateElement = armor.get(2); if (chestplateElement != null && chestplateElement.isJsonObject()) { JsonObject chestplate = chestplateElement.getAsJsonObject(); if (chestplate.get("internalname").getAsString().equals("OBSIDIAN_CHESTPLATE")) { JsonArray inventory = inventoryInfo.get("inv_contents"); for (int i = 0; i < inventory.size(); i++) { JsonElement itemElement = inventory.get(i); if (itemElement != null && itemElement.isJsonObject()) { JsonObject item = itemElement.getAsJsonObject(); if (item.get("internalname").getAsString().equals("OBSIDIAN")) { int count = 1; if (item.has("count")) { count = item.get("count").getAsInt(); } bonuses.addStat(SPEED, count / 20); } } } } } return bonuses; } private static Stats getStatForItem(String internalname, JsonObject item, JsonArray lore) { Stats stats = new Stats(); for (int i = 0; i < lore.size(); i++) { String line = lore.get(i).getAsString(); for (Map.Entry entry : STAT_PATTERN_MAP.entrySet()) { Matcher matcher = entry.getValue().matcher(Utils.cleanColour(line)); if (matcher.find()) { int bonus = Integer.parseInt(matcher.group(1)); stats.addStat(entry.getKey(), bonus); } } } if (internalname.equals("DAY_CRYSTAL") || internalname.equals("NIGHT_CRYSTAL")) { stats.addStat(STRENGTH, 2.5f); stats.addStat(DEFENCE, 2.5f); } if (internalname.equals("NEW_YEAR_CAKE_BAG") && item.has("item_contents")) { JsonArray bytesArr = item.get("item_contents").getAsJsonArray(); byte[] bytes = new byte[bytesArr.size()]; for (int i = 0; i < bytesArr.size(); i++) { bytes[i] = bytesArr.get(i).getAsByte(); } try { NBTTagCompound contents_nbt = CompressedStreamTools.readCompressed(new ByteArrayInputStream(bytes)); NBTTagList items = contents_nbt.getTagList("i", 10); HashSet cakes = new HashSet<>(); for (int j = 0; j < items.tagCount(); j++) { if (items.getCompoundTagAt(j).getKeySet().size() > 0) { NBTTagCompound nbt = items.getCompoundTagAt(j).getCompoundTag("tag"); if (nbt != null && nbt.hasKey("ExtraAttributes", 10)) { NBTTagCompound ea = nbt.getCompoundTag("ExtraAttributes"); if (ea.hasKey("new_years_cake")) { cakes.add(ea.getInteger("new_years_cake")); } } } } stats.addStat(HEALTH, cakes.size()); } catch (IOException e) { e.printStackTrace(); return stats; } } return stats; } private static Stats getItemBonuses(boolean talismanOnly, JsonArray... inventories) { JsonObject misc = Constants.MISC; if (misc == null) return null; JsonElement talisman_upgrades_element = misc.get("talisman_upgrades"); if (talisman_upgrades_element == null) return null; JsonObject talisman_upgrades = talisman_upgrades_element.getAsJsonObject(); HashMap itemBonuses = new HashMap<>(); for (JsonArray inventory : inventories) { for (int i = 0; i < inventory.size(); i++) { JsonElement itemElement = inventory.get(i); if (itemElement != null && itemElement.isJsonObject()) { JsonObject item = itemElement.getAsJsonObject(); String internalname = item.get("internalname").getAsString(); if (itemBonuses.containsKey(internalname)) { continue; } if (!talismanOnly || Utils.checkItemType(item.get("lore").getAsJsonArray(), true, "ACCESSORY", "HATCCESSORY") >= 0) { Stats itemBonus = getStatForItem(internalname, item, item.get("lore").getAsJsonArray()); itemBonuses.put(internalname, itemBonus); for (Map.Entry talisman_upgrades_item : talisman_upgrades.entrySet()) { JsonArray upgrades = talisman_upgrades_item.getValue().getAsJsonArray(); for (int j = 0; j < upgrades.size(); j++) { String upgrade = upgrades.get(j).getAsString(); if (upgrade.equals(internalname)) { itemBonuses.put(talisman_upgrades_item.getKey(), new Stats()); break; } } } } } } } Stats itemBonusesStats = new Stats(); for (Stats stats : itemBonuses.values()) { itemBonusesStats.add(stats); } return itemBonusesStats; } public static Stats getPetStatBonuses(JsonObject petsInfo) { JsonObject petsJson = Constants.PETS; JsonObject petnums = Constants.PETNUMS; if (petsJson == null || petnums == null) return new Stats(); if ( petsInfo != null && petsInfo.has("active_pet") && petsInfo.get("active_pet") != null && petsInfo.get("active_pet").isJsonObject() ) { JsonObject pet = petsInfo.get("active_pet").getAsJsonObject(); if ( pet.has("type") && pet.get("type") != null && pet.has("tier") && pet.get("tier") != null && pet.has("exp") && pet.get("exp") != null ) { String petname = pet.get("type").getAsString(); String tier = pet.get("tier").getAsString(); String heldItem = Utils.getElementAsString(pet.get("heldItem"), null); if (!petnums.has(petname)) { return new Stats(); } String tierNum = GuiProfileViewer.RARITY_TO_NUM.get(tier); float exp = pet.get("exp").getAsFloat(); if (tierNum == null) return new Stats(); if ( pet.has("heldItem") && !pet.get("heldItem").isJsonNull() && pet.get("heldItem").getAsString().equals("PET_ITEM_TIER_BOOST") ) { tierNum = "" + (Integer.parseInt(tierNum) + 1); } PetLeveling.PetLevel levelObj = PetLeveling.getPetLevelingForPet( petname, PetInfoOverlay.Rarity.valueOf(tier) ).getPetLevel(exp); float level = levelObj.getCurrentLevel(); float currentLevelRequirement = levelObj.getExpRequiredForNextLevel(); float maxXP = levelObj.getMaxLevel(); pet.addProperty("level", level); pet.addProperty("currentLevelRequirement", currentLevelRequirement); pet.addProperty("maxXP", maxXP); JsonObject petItem = NotEnoughUpdates.INSTANCE.manager.getItemInformation().get(petname + ";" + tierNum); if (petItem == null) return new Stats(); Stats stats = new Stats(); JsonObject petInfo = petnums.get(petname).getAsJsonObject(); if (petInfo.has(tier)) { JsonObject petInfoTier = petInfo.get(tier).getAsJsonObject(); if (petInfoTier == null || !petInfoTier.has("1") || !petInfoTier.has("100")) { return new Stats(); } JsonObject min = petInfoTier.get("1").getAsJsonObject(); JsonObject max = petInfoTier.get("100").getAsJsonObject(); float minMix = (100 - level) / 99f; float maxMix = (level - 1) / 99f; for (Map.Entry entry : max.get("statNums").getAsJsonObject().entrySet()) { float statMax = entry.getValue().getAsFloat(); float statMin = min.get("statNums").getAsJsonObject().get(entry.getKey()).getAsFloat(); float val = statMin * minMix + statMax * maxMix; stats.addStat(entry.getKey().toLowerCase(), (int) Math.floor(val)); } } if (heldItem != null) { HashMap petStatBoots = GuiProfileViewer.PET_STAT_BOOSTS.get(heldItem); HashMap petStatBootsMult = GuiProfileViewer.PET_STAT_BOOSTS_MULT.get(heldItem); if (petStatBoots != null) { for (Map.Entry entryBoost : petStatBoots.entrySet()) { String key = entryBoost.getKey().toLowerCase(); try { stats.addStat(key, entryBoost.getValue()); } catch (Exception ignored) {} } } if (petStatBootsMult != null) { for (Map.Entry entryBoost : petStatBootsMult.entrySet()) { String key = entryBoost.getKey().toLowerCase(); try { stats.scale(key, entryBoost.getValue()); } catch (Exception ignored) {} } } } return stats; } } return new Stats(); } private static float getStatMult(Map inventoryInfo) { float mult = 1f; JsonArray armor = inventoryInfo.get("inv_armor"); String fullset = getFullset(armor, -1); if (fullset != null && fullset.equals("SUPERIOR_DRAGON_")) { mult *= 1.05f; } for (int i = 0; i < armor.size(); i++) { JsonElement itemElement = armor.get(i); if (itemElement == null || !itemElement.isJsonObject()) continue; JsonObject item = itemElement.getAsJsonObject(); String reforge = Utils.getElementAsString(Utils.getElement(item, "ExtraAttributes.modifier"), ""); if (reforge.equals("renowned")) { mult *= 1.01f; } } return mult; } private static void applyLimits(Stats stats, Map inventoryInfo) { //>0 JsonArray armor = inventoryInfo.get("inv_armor"); String fullset = getFullset(armor, 3); if (fullset != null) { switch (fullset) { case "CHEAP_TUXEDO_": stats.statsJson.add(HEALTH, new JsonPrimitive(Math.min(75, stats.get(HEALTH)))); case "FANCY_TUXEDO_": stats.statsJson.add(HEALTH, new JsonPrimitive(Math.min(150, stats.get(HEALTH)))); case "ELEGANT_TUXEDO_": stats.statsJson.add(HEALTH, new JsonPrimitive(Math.min(250, stats.get(HEALTH)))); } } for (Map.Entry statEntry : stats.statsJson.entrySet()) { if ( statEntry.getKey().equals(CRIT_DAMAGE) || statEntry.getKey().equals(INTELLIGENCE) || statEntry.getKey().equals(BONUS_ATTACK_SPEED) ) continue; stats.statsJson.add(statEntry.getKey(), new JsonPrimitive(Math.max(0, statEntry.getValue().getAsFloat()))); } } public static Stats getStats( Map levelingInfo, Map inventoryInfo, JsonObject petsInfo, JsonObject profile ) { if (levelingInfo == null || inventoryInfo == null || profile == null) return null; JsonArray armor = inventoryInfo.get("inv_armor"); JsonArray inventory = inventoryInfo.get("inv_contents"); JsonArray talisman_bag = inventoryInfo.get("talisman_bag"); Stats passiveBonuses = getPassiveBonuses(levelingInfo, profile); Stats hotmBonuses = getHOTMBonuses(levelingInfo, profile); Stats armorBonuses = getItemBonuses(false, armor); Stats talismanBonuses = getItemBonuses(true, inventory, talisman_bag); if (passiveBonuses == null || armorBonuses == null || talismanBonuses == null) { return null; } Stats stats = getBaseStats(); if (stats == null) { return null; } Stats petBonus = getPetStatBonuses(petsInfo); stats = stats.add(passiveBonuses).add(armorBonuses).add(talismanBonuses).add(petBonus).add(hotmBonuses); stats.add(getSetBonuses(stats, inventoryInfo, levelingInfo, profile)); stats.scaleAll(getStatMult(inventoryInfo)); applyLimits(stats, inventoryInfo); return stats; } /** * Finds the Magical Power the player selected if applicable * * @param profileInfo profile information object * @return selected magical power as a String or null * @see SkyblockProfiles.SkyblockProfile#getLevelingInfo() */ public static @Nullable String getSelectedMagicalPower(JsonObject profileInfo) { String abs = "accessory_bag_storage"; if ( profileInfo == null || !profileInfo.has(abs) || !profileInfo.get(abs).isJsonObject() || !profileInfo.get(abs).getAsJsonObject().has("selected_power") ) { return null; } String selectedPower = profileInfo.get(abs).getAsJsonObject().get("selected_power").getAsString(); return selectedPower.substring(0, 1).toUpperCase() + selectedPower.substring(1); } public static @Nullable QuiverInfo getQuiverInfo(Map inventoryInfo, JsonObject profileInfo) { if (inventoryInfo == null || !inventoryInfo.containsKey("quiver")) { return null; } QuiverInfo quiverInfo = new QuiverInfo(); quiverInfo.arrows = new HashMap<>(); JsonArray quiver = inventoryInfo.get("quiver"); for (JsonElement quiverEntry : quiver) { if (quiverEntry == null || quiverEntry.isJsonNull() || !quiverEntry.isJsonObject()) { continue; } JsonObject stack = quiverEntry.getAsJsonObject(); if (!stack.has("internalname") || !stack.has("count")) { continue; } String internalName = stack.get("internalname").getAsString(); int count = stack.get("count").getAsInt(); quiverInfo.arrows.computeIfPresent(internalName, (key, existing) -> existing + count); quiverInfo.arrows.putIfAbsent(internalName, count); } quiverInfo.selectedArrow = Utils.getElementAsString(Utils.getElement(profileInfo, "item_data.favorite_arrow"), null); return quiverInfo; } public static class Stats { JsonObject statsJson = new JsonObject(); /*public float health; public float defence; public float strength; public float speed; public float crit_chance; public float crit_damage; public float bonus_attack_speed; public float intelligence; public float sea_creature_chance; public float magic_find; public float pet_luck;*/ public Stats(Stats... statses) { for (Stats stats : statses) { add(stats); } } /*@Override public String toString() { return String.format("{health=%s,defence=%s,strength=%s,speed=%s,crit_chance=%s,crit_damage=%s," + "bonus_attack_speed=%s,intelligence=%s,sea_creature_chance=%s,magic_find=%s,pet_luck=%s}", stats.get("health"), defence, strength, speed, crit_chance, crit_damage, bonus_attack_speed, intelligence, sea_creature_chance, magic_find, pet_luck ); }*/ public float get(String statName) { if (statsJson.has(statName)) { return statsJson.get(statName).getAsFloat(); } else { return 0; } } public Stats add(Stats stats) { for (Map.Entry statEntry : stats.statsJson.entrySet()) { if (statEntry.getValue().isJsonPrimitive() && ((JsonPrimitive) statEntry.getValue()).isNumber()) { if (!statsJson.has(statEntry.getKey())) { statsJson.add(statEntry.getKey(), statEntry.getValue()); } else { JsonPrimitive e = statsJson.get(statEntry.getKey()).getAsJsonPrimitive(); float statNum = e.getAsFloat() + statEntry.getValue().getAsFloat(); statsJson.add(statEntry.getKey(), new JsonPrimitive(statNum)); } } } return this; } public void scale(String statName, float scale) { if (statsJson.has(statName)) { statsJson.add(statName, new JsonPrimitive(statsJson.get(statName).getAsFloat() * scale)); } } public void scaleAll(float scale) { for (Map.Entry statEntry : statsJson.entrySet()) { statsJson.add(statEntry.getKey(), new JsonPrimitive(statEntry.getValue().getAsFloat() * scale)); } } public void addStat(String statName, float amount) { if (!statsJson.has(statName)) { statsJson.add(statName, new JsonPrimitive(amount)); } else { JsonPrimitive e = statsJson.get(statName).getAsJsonPrimitive(); statsJson.add(statName, new JsonPrimitive(e.getAsFloat() + amount)); } } } }