diff options
author | kr45732 <52721908+kr45732@users.noreply.github.com> | 2022-08-05 14:53:17 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-08-05 20:53:17 +0200 |
commit | 6d2c47744663309c4297a93ff9311e9074251fa1 (patch) | |
tree | 32cd1e14153dd21acf6ec8d5a41df298fe359e9d /src | |
parent | 1b6b70610fb2b486ecca664806b57b949526b388 (diff) | |
download | NotEnoughUpdates-6d2c47744663309c4297a93ff9311e9074251fa1.tar.gz NotEnoughUpdates-6d2c47744663309c4297a93ff9311e9074251fa1.tar.bz2 NotEnoughUpdates-6d2c47744663309c4297a93ff9311e9074251fa1.zip |
Add weight to pv (#201)
* Finished senither weight
* Fixed lily weight
* move file and add senither weight
* Impl weight
* Remove unnecessary stuff
* undo nw change
* fix stuff
* Update 2.1.md
* why on earth would you do this 🙂
Co-authored-by: nopo <noahogno@gmail.com>
Diffstat (limited to 'src')
17 files changed, 970 insertions, 1 deletions
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/GuiProfileViewer.java b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/GuiProfileViewer.java index 455bbf36..a21145d1 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/GuiProfileViewer.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/GuiProfileViewer.java @@ -31,6 +31,8 @@ import io.github.moulberry.notenoughupdates.cosmetics.ShaderManager; import io.github.moulberry.notenoughupdates.itemeditor.GuiElementTextField; import io.github.moulberry.notenoughupdates.profileviewer.bestiary.BestiaryPage; import io.github.moulberry.notenoughupdates.profileviewer.trophy.TrophyFishingPage; +import io.github.moulberry.notenoughupdates.profileviewer.weight.lily.LilyWeight; +import io.github.moulberry.notenoughupdates.profileviewer.weight.senither.SenitherWeight; import io.github.moulberry.notenoughupdates.util.Constants; import io.github.moulberry.notenoughupdates.util.SBInfo; import io.github.moulberry.notenoughupdates.util.Utils; @@ -100,6 +102,8 @@ import java.util.function.Supplier; import java.util.regex.Matcher; import java.util.regex.Pattern; +import static io.github.moulberry.notenoughupdates.util.Utils.roundToNearestInt; + public class GuiProfileViewer extends GuiScreen { public static final ResourceLocation pv_basic = new ResourceLocation("notenoughupdates:pv_basic.png"); public static final ResourceLocation pv_dung = new ResourceLocation("notenoughupdates:pv_dung.png"); @@ -4621,7 +4625,6 @@ public class GuiProfileViewer extends GuiScreen { .get("avg_buy") .getAsDouble()); String networthIRLMoney = Long.toString(Math.round(((networthInCookies * 325) / 675) * 4.99)); - if (mouseX > guiLeft + 8 && mouseX < guiLeft + 8 + fontRendererObj.getStringWidth("Net Worth: " + numberFormat.format(networth))) { if (mouseY > guiTop + 32 && mouseY < guiTop + 32 + fontRendererObj.FONT_HEIGHT) { @@ -4945,6 +4948,64 @@ public class GuiProfileViewer extends GuiScreen { 0 ); } + + renderWeight(mouseX, mouseY, skillInfo, profileInfo); + } + + private void renderWeight(int mouseX, int mouseY, JsonObject skillInfo, JsonObject profileInfo) { + if (skillInfo == null) { + return; + } + + if(Constants.WEIGHT == null) { + Utils.showOutdatedRepoNotification(); + return; + } + + FontRenderer fr = Minecraft.getMinecraft().fontRendererObj; + + SenitherWeight senitherWeight = new SenitherWeight(skillInfo); + LilyWeight lilyWeight = new LilyWeight(skillInfo, profileInfo); + + Utils.drawStringCentered( + EnumChatFormatting.GREEN + "Senither Weight: " + EnumChatFormatting.GOLD + numberFormat.format(roundToNearestInt(senitherWeight.getTotalWeight().getRaw())), + fr, + guiLeft + 63, + guiTop + 18, + true, + 0 + ); + + int textWidth = fontRendererObj.getStringWidth("Senither Weight: " + numberFormat.format(roundToNearestInt(senitherWeight.getTotalWeight().getRaw()))); + if (mouseX > guiLeft + 63 - textWidth / 2 && + mouseX < guiLeft + 63 + textWidth / 2) { + if (mouseY > guiTop + 12 && mouseY < guiTop + 12 + fontRendererObj.FONT_HEIGHT) { + tooltipToDisplay = new ArrayList<>(); + tooltipToDisplay.add(EnumChatFormatting.GREEN + "Skills: " + EnumChatFormatting.GOLD + numberFormat.format(roundToNearestInt(senitherWeight.getSkillsWeight().getWeightStruct().getRaw()))); + tooltipToDisplay.add(EnumChatFormatting.GREEN + "Slayer: " + EnumChatFormatting.GOLD + numberFormat.format(roundToNearestInt(senitherWeight.getSlayerWeight().getWeightStruct().getRaw()))); + tooltipToDisplay.add(EnumChatFormatting.GREEN + "Dungeons: " + EnumChatFormatting.GOLD + numberFormat.format(roundToNearestInt(senitherWeight.getDungeonsWeight().getWeightStruct().getRaw()))); + } + } + + Utils.drawStringCentered( + EnumChatFormatting.GREEN + "Lily Weight: " + EnumChatFormatting.GOLD + numberFormat.format(roundToNearestInt(lilyWeight.getTotalWeight().getRaw())), + fr, + guiLeft + 63, + guiTop + 28, + true, + 0 + ); + + int fontWidth = fontRendererObj.getStringWidth("Lily Weight: " + numberFormat.format(roundToNearestInt(lilyWeight.getTotalWeight().getRaw()))); + if (mouseX > guiLeft + 63 - fontWidth / 2 && + mouseX < guiLeft + 63 + fontWidth / 2) { + if (mouseY > guiTop + 22 && mouseY < guiTop + 22 + fontRendererObj.FONT_HEIGHT) { + tooltipToDisplay = new ArrayList<>(); + tooltipToDisplay.add(EnumChatFormatting.GREEN + "Skills: " + EnumChatFormatting.GOLD + numberFormat.format(roundToNearestInt(lilyWeight.getSkillsWeight().getWeightStruct().getRaw()))); + tooltipToDisplay.add(EnumChatFormatting.GREEN + "Slayer: " + EnumChatFormatting.GOLD + numberFormat.format(roundToNearestInt(lilyWeight.getSlayerWeight().getWeightStruct().getRaw()))); + tooltipToDisplay.add(EnumChatFormatting.GREEN + "Dungeons: " + EnumChatFormatting.GOLD + numberFormat.format(roundToNearestInt(lilyWeight.getDungeonsWeight().getWeightStruct().getRaw()))); + } + } } private void renderGoldBar(float x, float y, float xSize) { diff --git a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/ProfileViewer.java b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/ProfileViewer.java index 4797254d..68dca09c 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/ProfileViewer.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/ProfileViewer.java @@ -892,6 +892,16 @@ public class ProfileViewer { float experience_skill_catacombs = Utils.getElementAsFloat(Utils.getElement(profileInfo, "dungeons.dungeon_types.catacombs.experience"), 0); + float experience_skill_healer = + Utils.getElementAsFloat(Utils.getElement(profileInfo, "dungeons.player_classes.healer.experience"), 0); + float experience_skill_archer = + Utils.getElementAsFloat(Utils.getElement(profileInfo, "dungeons.player_classes.archer.experience"), 0); + float experience_skill_tank = + Utils.getElementAsFloat(Utils.getElement(profileInfo, "dungeons.player_classes.tank.experience"), 0); + float experience_skill_mage = + Utils.getElementAsFloat(Utils.getElement(profileInfo, "dungeons.player_classes.mage.experience"), 0); + float experience_skill_berserk = + Utils.getElementAsFloat(Utils.getElement(profileInfo, "dungeons.player_classes.berserk.experience"), 0); float experience_slayer_zombie = Utils.getElementAsFloat(Utils.getElement(profileInfo, "slayer_bosses.zombie.xp"), 0); @@ -928,6 +938,11 @@ public class ProfileViewer { skillInfo.addProperty("experience_skill_hotm", experience_skill_hotm); skillInfo.addProperty("experience_skill_catacombs", experience_skill_catacombs); + skillInfo.addProperty("experience_skill_healer", experience_skill_healer); + skillInfo.addProperty("experience_skill_tank", experience_skill_tank); + skillInfo.addProperty("experience_skill_mage", experience_skill_mage); + skillInfo.addProperty("experience_skill_archer", experience_skill_archer); + skillInfo.addProperty("experience_skill_berserk", experience_skill_berserk); skillInfo.addProperty("experience_slayer_zombie", experience_slayer_zombie); skillInfo.addProperty("experience_slayer_spider", experience_slayer_spider); diff --git a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/weight/lily/LilyDungeonsWeight.java b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/weight/lily/LilyDungeonsWeight.java new file mode 100644 index 00000000..31748535 --- /dev/null +++ b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/weight/lily/LilyDungeonsWeight.java @@ -0,0 +1,145 @@ +/* + * 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 <https://www.gnu.org/licenses/>. + */ + +package io.github.moulberry.notenoughupdates.profileviewer.weight.lily; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import io.github.moulberry.notenoughupdates.profileviewer.weight.weight.DungeonsWeight; +import io.github.moulberry.notenoughupdates.profileviewer.weight.weight.WeightStruct; +import io.github.moulberry.notenoughupdates.util.Constants; +import io.github.moulberry.notenoughupdates.util.Utils; +import java.util.Map; + +public class LilyDungeonsWeight extends DungeonsWeight { + + private final JsonObject profileJson; + + public LilyDungeonsWeight(JsonObject player, JsonObject profileJson) { + super(player); + this.profileJson = profileJson; + } + + @Override + public void getDungeonWeight() { + double level = Utils.getElementAsFloat(Utils.getElement(player, "level_skill_catacombs"), 0); + float cataXP = Utils.getElementAsFloat(Utils.getElement(player, "experience_skill_catacombs"), 0); + + double extra = 0; + double n = 0; + if (cataXP < 569809640) { + n = 0.2 * Math.pow(level / 50, 1.538679118869934); + } else { + extra = 500.0 * Math.pow((cataXP - CATACOMBS_LEVEL_50_XP) / 142452410.0, 1.0 / 1.781925776625157); + } + + if (level != 0) { + if (cataXP < 569809640) { + weightStruct.add( + new WeightStruct(1.2733079672009226 * ((Math.pow(1.18340401286164044, (level + 1)) - 1.05994990217254) * (1 + n))) + ); + } else { + weightStruct.add(new WeightStruct((4100 + extra) * 2)); + } + } + } + + public void getDungeonCompletionWeight(String cataMode) { + double max1000 = 0; + double mMax1000 = 0; + JsonObject dungeonsCompletionWorth = Utils.getElement(Constants.WEIGHT, "lily.dungeons.completion_worth").getAsJsonObject(); + for (Map.Entry<String, JsonElement> dcwEntry : dungeonsCompletionWorth.entrySet()) { + if (dcwEntry.getKey().startsWith("catacombs_")) { + max1000 += dcwEntry.getValue().getAsDouble(); + } else { + mMax1000 += dcwEntry.getValue().getAsDouble(); + } + } + max1000 *= 1000; + mMax1000 *= 1000; + double upperBound = 1500; + if (cataMode.equals("normal")) { + if (Utils.getElement(profileJson, "dungeons.dungeon_types.catacombs.tier_completions") == null) { + return; + } + + double score = 0; + for (Map.Entry<String, JsonElement> normalFloor : Utils + .getElement(profileJson, "dungeons.dungeon_types.catacombs.tier_completions") + .getAsJsonObject() + .entrySet()) { + int amount = normalFloor.getValue().getAsInt(); + double excess = 0; + if (amount > 1000) { + excess = amount - 1000; + amount = 1000; + } + + double floorScore = amount * dungeonsCompletionWorth.get("catacombs_" + normalFloor.getKey()).getAsDouble(); + if (excess > 0) floorScore *= Math.log(excess / 1000 + 1) / Math.log(7.5) + 1; + score += floorScore; + } + + weightStruct.add(new WeightStruct(score / max1000 * upperBound * 2)); + } else { + JsonObject dungeonsCompletionBuffs = Utils.getElement(Constants.WEIGHT, "lily.dungeons.completion_buffs").getAsJsonObject(); + + if (Utils.getElement(profileJson, "dungeons.dungeon_types.master_catacombs.tier_completions") == null) { + return; + } + + for (Map.Entry<String, JsonElement> masterFloor : Utils + .getElement(profileJson, "dungeons.dungeon_types.master_catacombs.tier_completions") + .getAsJsonObject() + .entrySet()) { + if (dungeonsCompletionBuffs.get(masterFloor.getKey()) != null) { + int amount = masterFloor.getValue().getAsInt(); + double threshold = 20; + if (amount >= threshold) { + upperBound += dungeonsCompletionBuffs.get(masterFloor.getKey()).getAsInt(); + } else { + upperBound += + dungeonsCompletionBuffs.get(masterFloor.getKey()).getAsInt() * Math.pow((amount / threshold), 1.840896416); + } + } + } + + double masterScore = 0; + for (Map.Entry<String, JsonElement> masterFloor : Utils + .getElement(profileJson, "dungeons.dungeon_types.master_catacombs.tier_completions") + .getAsJsonObject() + .entrySet()) { + int amount = masterFloor.getValue().getAsInt(); + double excess = 0; + if (amount > 1000) { + excess = amount - 1000; + amount = 1000; + } + + double floorScore = amount * dungeonsCompletionWorth.get("master_catacombs_" + masterFloor.getKey()).getAsDouble(); + if (excess > 0) { + floorScore *= (Math.log((excess / 1000) + 1) / Math.log(6)) + 1; + } + masterScore += floorScore; + } + + weightStruct.add(new WeightStruct((masterScore / mMax1000) * upperBound * 2)); + } + } +} diff --git a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/weight/lily/LilySkillsWeight.java b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/weight/lily/LilySkillsWeight.java new file mode 100644 index 00000000..bbe07a5a --- /dev/null +++ b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/weight/lily/LilySkillsWeight.java @@ -0,0 +1,101 @@ +/* + * 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 <https://www.gnu.org/licenses/>. + */ + +package io.github.moulberry.notenoughupdates.profileviewer.weight.lily; + +import static io.github.moulberry.notenoughupdates.profileviewer.weight.weight.Weight.SKILL_NAMES; + +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import io.github.moulberry.notenoughupdates.profileviewer.ProfileViewer; +import io.github.moulberry.notenoughupdates.profileviewer.weight.weight.SkillsWeight; +import io.github.moulberry.notenoughupdates.profileviewer.weight.weight.WeightStruct; +import io.github.moulberry.notenoughupdates.util.Constants; +import io.github.moulberry.notenoughupdates.util.Utils; + +public class LilySkillsWeight extends SkillsWeight { + + public LilySkillsWeight(JsonObject player) { + super(player); + } + + @Override + public void getSkillsWeight(String skillName) { + double skillAverage = 0; + for (String skill : SKILL_NAMES) { + skillAverage += + (int) ProfileViewer.getLevel( + Utils.getElement(Constants.LEVELING, "leveling_xp").getAsJsonArray(), + Utils.getElementAsInt(Utils.getElement(player, "experience_skill_" + skill), 0), + 60, + false + ) + .level; + } + skillAverage /= SKILL_NAMES.size(); + + float currentExp = Utils.getElementAsFloat(Utils.getElement(player, "experience_skill_" + skillName), 0); + int currentLevel = (int) ProfileViewer.getLevel( + Utils.getElement(Constants.LEVELING, "leveling_xp").getAsJsonArray(), + currentExp, + 60, + false + ) + .level; + + JsonArray srwTable = Utils.getElement(Constants.WEIGHT, "lily.skills.ratio_weight." + skillName).getAsJsonArray(); + double base = + ( + (12 * Math.pow((skillAverage / 60), 2.44780217148309)) * + srwTable.get(currentLevel).getAsDouble() * + srwTable.get(srwTable.size() - 1).getAsDouble() + ) + + (srwTable.get(srwTable.size() - 1).getAsDouble() * Math.pow(currentLevel / 60.0, Math.pow(2, 0.5))); + base *= 1.8162162162162162; + double overflow = 0; + if (currentExp > 111672425) { + double factor = Utils.getElementAsFloat(Utils.getElement(Constants.WEIGHT, "lily.skills.factors." + skillName), 0); + double effectiveOver = effectiveXP(currentExp - 111672425, factor); + double t = + (effectiveOver / 111672425) * + Utils.getElementAsFloat(Utils.getElement(Constants.WEIGHT, "lily.skills.overflow_multipliers." + skillName), 0); + if (t > 0) { + overflow += 1.8162162162162162 * t; + } + } + + weightStruct.add(new WeightStruct(base, overflow)); + } + + private double effectiveXP(double xp, double factor) { + if (xp < 111672425) { + return xp; + } else { + double remainingXP = xp; + double z = 0; + for (int i = 0; i <= (int) (xp / 111672425); i++) { + if (remainingXP >= 111672425) { + remainingXP -= 111672425; + z += Math.pow(factor, i); + } + } + return z * 111672425; + } + } +} diff --git a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/weight/lily/LilySlayerWeight.java b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/weight/lily/LilySlayerWeight.java new file mode 100644 index 00000000..5c55633a --- /dev/null +++ b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/weight/lily/LilySlayerWeight.java @@ -0,0 +1,91 @@ +/* + * 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 <https://www.gnu.org/licenses/>. + */ + +package io.github.moulberry.notenoughupdates.profileviewer.weight.lily; + +import com.google.gson.JsonObject; +import io.github.moulberry.notenoughupdates.profileviewer.weight.weight.SlayerWeight; +import io.github.moulberry.notenoughupdates.profileviewer.weight.weight.WeightStruct; +import io.github.moulberry.notenoughupdates.util.Constants; +import io.github.moulberry.notenoughupdates.util.Utils; + +public class LilySlayerWeight extends SlayerWeight { + + public LilySlayerWeight(JsonObject player) { + super(player); + } + + public void getSlayerWeight(String slayerName) { + int currentSlayerXp = Utils.getElementAsInt(Utils.getElement(player, "experience_slayer_" + slayerName), 0); + + double score; + double d = currentSlayerXp / 100000.0; + if (currentSlayerXp >= 6416) { + double D = (d - Math.pow(3, (-5.0 / 2))) * (d + Math.pow(3, -5.0 / 2)); + double u = Math.cbrt(3 * (d + Math.sqrt(D))); + double v = Math.cbrt(3 * (d - Math.sqrt(D))); + score = u + v - 1; + } else { + score = Math.sqrt(4.0 / 3) * Math.cos(Math.acos(d * Math.pow(3, 5.0 / 2)) / 3) - 1; + } + + double scaleFactor = Utils.getElementAsFloat( + Utils.getElement(Constants.WEIGHT, "lily.slayer.deprecation_scaling." + slayerName), + 0 + ); + int intScore = (int) score; + double distance = currentSlayerXp - actualInt(intScore); + double effectiveDistance = distance * Math.pow(scaleFactor, intScore); + double effectiveScore = effectiveInt(intScore, scaleFactor) + effectiveDistance; + double weight; + switch (slayerName) { + case "zombie": + weight = (effectiveScore / 8390.64) + (currentSlayerXp / 1000000.0); + break; + case "spider": + weight = (effectiveScore / 7019.57) + ((currentSlayerXp * 1.6) / 1000000); + break; + case "wolf": + weight = (effectiveScore / 2982.06) + ((currentSlayerXp * 3.6) / 1000000); + break; + case "enderman": + weight = (effectiveScore / 1118.81) + ((currentSlayerXp * 10.0) / 1000000); + break; + case "blaze": + weight = (effectiveScore / 751.281) + ((currentSlayerXp * 15.0) / 1000000); + break; + default: + return; + } + + weightStruct.add(new WeightStruct(2 * weight)); + } + + private double actualInt(int intScore) { + return (((Math.pow(intScore, 3) / 6) + (Math.pow(intScore, 2) / 2) + (intScore / 3.0)) * 100000); + } + + private double effectiveInt(int intScore, double scaleFactor) { + double total = 0; + for (int k = 0; k < intScore; k++) { + total += (Math.pow((k + 1), 2) + (k + 1)) * Math.pow(scaleFactor, (k + 1)); + } + return 1000000 * total * (0.05 / scaleFactor); + } +} diff --git a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/weight/lily/LilyWeight.java b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/weight/lily/LilyWeight.java new file mode 100644 index 00000000..9a851f12 --- /dev/null +++ b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/weight/lily/LilyWeight.java @@ -0,0 +1,48 @@ +/* + * 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 <https://www.gnu.org/licenses/>. + */ + +package io.github.moulberry.notenoughupdates.profileviewer.weight.lily; + +import com.google.gson.JsonObject; +import io.github.moulberry.notenoughupdates.profileviewer.weight.weight.Weight; + +public class LilyWeight extends Weight { + + public LilyWeight(JsonObject player, JsonObject profileJson) { + super(new LilySlayerWeight(player), new LilySkillsWeight(player), new LilyDungeonsWeight(player, profileJson)); + } + + @Override + public void calculateWeight() { + slayerWeight.getWeightStruct().reset(); + skillsWeight.getWeightStruct().reset(); + dungeonsWeight.getWeightStruct().reset(); + + for (String slayerName : SLAYER_NAMES) { + slayerWeight.getSlayerWeight(slayerName); + } + for (String skillName : SKILL_NAMES) { + skillsWeight.getSkillsWeight(skillName); + } + + dungeonsWeight.getDungeonWeight(); + ((LilyDungeonsWeight) dungeonsWeight).getDungeonCompletionWeight("normal"); + ((LilyDungeonsWeight) dungeonsWeight).getDungeonCompletionWeight("master"); + } +} diff --git a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/weight/senither/SenitherDungeonsWeight.java b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/weight/senither/SenitherDungeonsWeight.java new file mode 100644 index 00000000..198d34c8 --- /dev/null +++ b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/weight/senither/SenitherDungeonsWeight.java @@ -0,0 +1,80 @@ +/* + * 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 <https://www.gnu.org/licenses/>. + */ + +package io.github.moulberry.notenoughupdates.profileviewer.weight.senither; + +import com.google.gson.JsonObject; +import io.github.moulberry.notenoughupdates.profileviewer.ProfileViewer; +import io.github.moulberry.notenoughupdates.profileviewer.weight.weight.DungeonsWeight; +import io.github.moulberry.notenoughupdates.profileviewer.weight.weight.WeightStruct; +import io.github.moulberry.notenoughupdates.util.Constants; +import io.github.moulberry.notenoughupdates.util.Utils; + +public class SenitherDungeonsWeight extends DungeonsWeight { + + public SenitherDungeonsWeight(JsonObject player) { + super(player); + } + + public void getClassWeight(String className) { + float currentClassXp = Utils.getElementAsFloat(Utils.getElement(player, "experience_skill_" + className), 0); + double currentClassLevel = ProfileViewer.getLevel( + Utils.getElement(Constants.LEVELING, "catacombs").getAsJsonArray(), + currentClassXp, + Utils.getElementAsInt(Utils.getElement(Constants.LEVELING, "leveling_caps.catacombs"), 50), + false + ) + .level; + double base = + Math.pow(currentClassLevel, 4.5) * + Utils.getElementAsFloat(Utils.getElement(Constants.WEIGHT, "senither.dungeons.classes." + className), 0); + + if (currentClassXp <= CATACOMBS_LEVEL_50_XP) { + weightStruct.add(new WeightStruct(base)); + return; + } + + double remaining = currentClassXp - CATACOMBS_LEVEL_50_XP; + double splitter = (4 * CATACOMBS_LEVEL_50_XP) / base; + weightStruct.add(new WeightStruct(Math.floor(base), Math.pow(remaining / splitter, 0.968))); + } + + @Override + public void getDungeonWeight() { + float catacombsSkillXp = Utils.getElementAsFloat(Utils.getElement(player, "experience_skill_catacombs"), 0); + + double level = ProfileViewer.getLevel( + Utils.getElement(Constants.LEVELING, "catacombs").getAsJsonArray(), + catacombsSkillXp, + Utils.getElementAsInt(Utils.getElement(Constants.LEVELING, "leveling_caps.catacombs"), 50), + false + ) + .level; + double base = Math.pow(level, 4.5) * Utils.getElementAsFloat(Utils.getElement(Constants.WEIGHT, "senither.dungeons.catacombs"), 0); + + if (catacombsSkillXp <= CATACOMBS_LEVEL_50_XP) { + weightStruct.add(new WeightStruct(base)); + return; + } + + double remaining = catacombsSkillXp - CATACOMBS_LEVEL_50_XP; + double splitter = (4 * CATACOMBS_LEVEL_50_XP) / base; + weightStruct.add(new WeightStruct(Math.floor(base), Math.pow(remaining / splitter, 0.968))); + } +} diff --git a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/weight/senither/SenitherSkillsWeight.java b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/weight/senither/SenitherSkillsWeight.java new file mode 100644 index 00000000..081cab6d --- /dev/null +++ b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/weight/senither/SenitherSkillsWeight.java @@ -0,0 +1,66 @@ +/* + * 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 <https://www.gnu.org/licenses/>. + */ + +package io.github.moulberry.notenoughupdates.profileviewer.weight.senither; + +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import io.github.moulberry.notenoughupdates.profileviewer.ProfileViewer; +import io.github.moulberry.notenoughupdates.profileviewer.weight.weight.SkillsWeight; +import io.github.moulberry.notenoughupdates.profileviewer.weight.weight.WeightStruct; +import io.github.moulberry.notenoughupdates.util.Constants; +import io.github.moulberry.notenoughupdates.util.Utils; + +public class SenitherSkillsWeight extends SkillsWeight { + + public SenitherSkillsWeight(JsonObject player) { + super(player); + } + + @Override + public void getSkillsWeight(String skillName) { + JsonArray curWeights = Utils.getElement(Constants.WEIGHT, "senither.skills." + skillName).getAsJsonArray(); + double exponent = curWeights.get(0).getAsDouble(); + double divider = curWeights.get(1).getAsDouble(); + + float currentSkillXp = Utils.getElementAsFloat(Utils.getElement(player, "experience_skill_" + skillName), 0); + + if (currentSkillXp > 0) { + int maxLevel = skillName.equals("farming") + ? 60 + : Utils.getElementAsInt(Utils.getElement(Constants.LEVELING, "leveling_caps." + skillName), 50); + double level = ProfileViewer.getLevel( + Utils.getElement(Constants.LEVELING, "leveling_xp").getAsJsonArray(), + currentSkillXp, + maxLevel, + false + ) + .level; + + double maxLevelExp = maxLevel == 50 ? 55172425 : 111672425; + double base = Math.pow(level * 10, 0.5 + exponent + (level / 100)) / 1250; + if (currentSkillXp <= maxLevelExp) { + weightStruct.add(new WeightStruct(base)); + return; + } + + weightStruct.add(new WeightStruct(Math.round(base), Math.pow((currentSkillXp - maxLevelExp) / divider, 0.968))); + } + } +} diff --git a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/weight/senither/SenitherSlayerWeight.java b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/weight/senither/SenitherSlayerWeight.java new file mode 100644 index 00000000..3b7b2498 --- /dev/null +++ b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/weight/senither/SenitherSlayerWeight.java @@ -0,0 +1,66 @@ +/* + * 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 <https://www.gnu.org/licenses/>. + */ + +package io.github.moulberry.notenoughupdates.profileviewer.weight.senither; + +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import io.github.moulberry.notenoughupdates.profileviewer.weight.weight.SlayerWeight; +import io.github.moulberry.notenoughupdates.profileviewer.weight.weight.WeightStruct; +import io.github.moulberry.notenoughupdates.util.Constants; +import io.github.moulberry.notenoughupdates.util.Utils; + +public class SenitherSlayerWeight extends SlayerWeight { + + public SenitherSlayerWeight(JsonObject player) { + super(player); + } + + public void getSlayerWeight(String slayerName) { + if (slayerName.equals("blaze")) { + return; + } + + JsonArray curWeights = Utils.getElement(Constants.WEIGHT, "senither.slayer." + slayerName).getAsJsonArray(); + double divider = curWeights.get(0).getAsDouble(); + double modifier = curWeights.get(1).getAsDouble(); + + int currentSlayerXp = Utils.getElementAsInt(Utils.getElement(player, "experience_slayer_" + slayerName), 0); + + if (currentSlayerXp <= 1000000) { + weightStruct.add(new WeightStruct(currentSlayerXp == 0 ? 0 : currentSlayerXp / divider)); + return; + } + + double base = 1000000 / divider; + double remaining = currentSlayerXp - 1000000; + double overflow = 0; + double initialModifier = modifier; + + while (remaining > 0) { + double left = Math.min(remaining, 1000000); + + overflow += Math.pow(left / (divider * (1.5 + modifier)), 0.942); + modifier += initialModifier; + remaining -= left; + } + + weightStruct.add(new WeightStruct(base, overflow)); + } +} diff --git a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/weight/senither/SenitherWeight.java b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/weight/senither/SenitherWeight.java new file mode 100644 index 00000000..e0a2cf36 --- /dev/null +++ b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/weight/senither/SenitherWeight.java @@ -0,0 +1,50 @@ +/* + * 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 <https://www.gnu.org/licenses/>. + */ + +package io.github.moulberry.notenoughupdates.profileviewer.weight.senither; + +import com.google.gson.JsonObject; +import io.github.moulberry.notenoughupdates.profileviewer.weight.weight.Weight; + +public class SenitherWeight extends Weight { + + public SenitherWeight(JsonObject player) { + super(new SenitherSlayerWeight(player), new SenitherSkillsWeight(player), new SenitherDungeonsWeight(player)); + } + + @Override + public void calculateWeight() { + slayerWeight.getWeightStruct().reset(); + skillsWeight.getWeightStruct().reset(); + dungeonsWeight.getWeightStruct().reset(); + + for (String slayerName : SLAYER_NAMES) { + slayerWeight.getSlayerWeight(slayerName); + } + + for (String skillName : SKILL_NAMES) { + skillsWeight.getSkillsWeight(skillName); + } + + dungeonsWeight.getDungeonWeight(); + for (String dungeonClassName : DUNGEON_CLASS_NAMES) { + ((SenitherDungeonsWeight) dungeonsWeight).getClassWeight(dungeonClassName); + } + } +} diff --git a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/weight/weight/DungeonsWeight.java b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/weight/weight/DungeonsWeight.java new file mode 100644 index 00000000..bab0346c --- /dev/null +++ b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/weight/weight/DungeonsWeight.java @@ -0,0 +1,41 @@ +/* + * 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 <https://www.gnu.org/licenses/>. + */ + +package io.github.moulberry.notenoughupdates.profileviewer.weight.weight; + +import com.google.gson.JsonObject; + +public abstract class DungeonsWeight { + + protected static final long CATACOMBS_LEVEL_50_XP = 569809640; + + protected final JsonObject player; + protected final WeightStruct weightStruct; + + public DungeonsWeight(JsonObject player) { + this.player = player; + this.weightStruct = new WeightStruct(); + } + + public WeightStruct getWeightStruct() { + return weightStruct; + } + + public abstract void getDungeonWeight(); +} diff --git a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/weight/weight/SkillsWeight.java b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/weight/weight/SkillsWeight.java new file mode 100644 index 00000000..b5e4e2b5 --- /dev/null +++ b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/weight/weight/SkillsWeight.java @@ -0,0 +1,39 @@ +/* + * 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 <https://www.gnu.org/licenses/>. + */ + +package io.github.moulberry.notenoughupdates.profileviewer.weight.weight; + +import com.google.gson.JsonObject; + +public abstract class SkillsWeight { + + protected final JsonObject player; + protected final WeightStruct weightStruct; + + public SkillsWeight(JsonObject player) { + this.player = player; + this.weightStruct = new WeightStruct(); + } + + public WeightStruct getWeightStruct() { + return weightStruct; + } + + public abstract void getSkillsWeight(String skillName); +} diff --git a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/weight/weight/SlayerWeight.java b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/weight/weight/SlayerWeight.java new file mode 100644 index 00000000..1ec83689 --- /dev/null +++ b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/weight/weight/SlayerWeight.java @@ -0,0 +1,39 @@ +/* + * 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 <https://www.gnu.org/licenses/>. + */ + +package io.github.moulberry.notenoughupdates.profileviewer.weight.weight; + +import com.google.gson.JsonObject; + +public abstract class SlayerWeight { + + protected final JsonObject player; + protected final WeightStruct weightStruct; + + public SlayerWeight(JsonObject player) { + this.player = player; + this.weightStruct = new WeightStruct(); + } + + public WeightStruct getWeightStruct() { + return weightStruct; + } + + public abstract void getSlayerWeight(String slayerName); +} diff --git a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/weight/weight/Weight.java b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/weight/weight/Weight.java new file mode 100644 index 00000000..f3e0cef3 --- /dev/null +++ b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/weight/weight/Weight.java @@ -0,0 +1,67 @@ +/* + * 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 <https://www.gnu.org/licenses/>. + */ + +package io.github.moulberry.notenoughupdates.profileviewer.weight.weight; + +import java.util.Arrays; +import java.util.List; + +public abstract class Weight { + + protected static final List<String> SLAYER_NAMES = Arrays.asList("wolf", "zombie", "spider", "enderman", "blaze"); + protected static final List<String> DUNGEON_CLASS_NAMES = Arrays.asList("healer", "mage", "berserk", "archer", "tank"); + public static final List<String> SKILL_NAMES = Arrays.asList( + "taming", + "mining", + "foraging", + "enchanting", + "farming", + "combat", + "fishing", + "alchemy" + ); + protected final SlayerWeight slayerWeight; + protected final SkillsWeight skillsWeight; + protected final DungeonsWeight dungeonsWeight; + + public Weight(SlayerWeight slayerWeight, SkillsWeight skillsWeight, DungeonsWeight dungeonsWeight) { + this.slayerWeight = slayerWeight; + this.skillsWeight = skillsWeight; + this.dungeonsWeight = dungeonsWeight; + this.calculateWeight(); + } + + public WeightStruct getTotalWeight() { + return new WeightStruct().add(slayerWeight.getWeightStruct()).add(skillsWeight.getWeightStruct()).add(dungeonsWeight.getWeightStruct()); + } + + public SlayerWeight getSlayerWeight() { + return slayerWeight; + } + + public SkillsWeight getSkillsWeight() { + return skillsWeight; + } + + public DungeonsWeight getDungeonsWeight() { + return dungeonsWeight; + } + + protected abstract void calculateWeight(); +} diff --git a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/weight/weight/WeightStruct.java b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/weight/weight/WeightStruct.java new file mode 100644 index 00000000..924dcb40 --- /dev/null +++ b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/weight/weight/WeightStruct.java @@ -0,0 +1,54 @@ +/* + * 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 <https://www.gnu.org/licenses/>. + */ + +package io.github.moulberry.notenoughupdates.profileviewer.weight.weight; + +public class WeightStruct { + + private double base; + private double overflow; + + public WeightStruct() { + this(0, 0); + } + + public WeightStruct(double base) { + this(base, 0); + } + + public WeightStruct(double base, double overflow) { + this.base = base; + this.overflow = overflow; + } + + public WeightStruct add(WeightStruct o) { + this.base += o.base; + this.overflow += o.overflow; + return this; + } + + public double getRaw() { + return base + overflow; + } + + public void reset() { + this.base = 0; + this.overflow = 0; + } +} diff --git a/src/main/java/io/github/moulberry/notenoughupdates/util/Constants.java b/src/main/java/io/github/moulberry/notenoughupdates/util/Constants.java index 5279ed73..1d226dc8 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/util/Constants.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/util/Constants.java @@ -70,6 +70,7 @@ public class Constants { public static JsonObject FAIRYSOULS; public static JsonObject REFORGESTONES; public static JsonObject TROPHYFISH; + public static JsonObject WEIGHT; private static final ReentrantLock lock = new ReentrantLock(); @@ -90,6 +91,7 @@ public class Constants { FAIRYSOULS = Utils.getConstant("fairy_souls", gson); REFORGESTONES = Utils.getConstant("reforgestones", gson); TROPHYFISH = Utils.getConstant("trophyfish", gson); + WEIGHT = Utils.getConstant("weight", gson); } catch (Exception ex) { ex.printStackTrace(); } finally { diff --git a/src/main/java/io/github/moulberry/notenoughupdates/util/Utils.java b/src/main/java/io/github/moulberry/notenoughupdates/util/Utils.java index f45b840c..4d546505 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/util/Utils.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/util/Utils.java @@ -668,6 +668,10 @@ public class Utils { return (float) Math.round(value * scale) / scale; } + public static int roundToNearestInt(double value) { + return (int) Math.round(value); + } + // Parses Roman numerals, allowing for single character irregular subtractive notation (e.g. IL is 49, IIL is invalid) public static int parseRomanNumeral(String input) { int prevVal = 0; |