diff --git a/src/main/java/net/Indyuce/mmoitems/api/crafting/ConfigMMOItem.java b/src/main/java/net/Indyuce/mmoitems/api/crafting/ConfigMMOItem.java index 75741cf8..3d0cdace 100644 --- a/src/main/java/net/Indyuce/mmoitems/api/crafting/ConfigMMOItem.java +++ b/src/main/java/net/Indyuce/mmoitems/api/crafting/ConfigMMOItem.java @@ -8,6 +8,7 @@ import net.Indyuce.mmoitems.MMOItems; import net.Indyuce.mmoitems.api.Type; import net.Indyuce.mmoitems.api.item.template.MMOItemTemplate; import net.Indyuce.mmoitems.api.player.RPGPlayer; +import org.jetbrains.annotations.NotNull; public class ConfigMMOItem { private final MMOItemTemplate template; @@ -32,7 +33,14 @@ public class ConfigMMOItem { this.amount = Math.max(1, amount); } - public ItemStack generate(RPGPlayer player) { + /** + * This actually generates the item the player wanted to craft. + * + * @param player Player to roll RNG in base of + * + * @return A freshly-crafted item to be used by the player. + */ + @NotNull public ItemStack generate(@NotNull RPGPlayer player) { ItemStack item = template.newBuilder(player).build().newBuilder().build(); item.setAmount(amount); return item; @@ -47,7 +55,7 @@ public class ConfigMMOItem { * needs to be displayed */ public ItemStack getPreview() { - return preview == null ? (preview = template.newBuilder(0, null).build().newBuilder().build()).clone() : preview.clone(); + return preview == null ? (preview = template.newBuilder(0, null).build().newBuilder().build(true)).clone() : preview.clone(); } public int getAmount() { diff --git a/src/main/java/net/Indyuce/mmoitems/api/crafting/ingredient/Ingredient.java b/src/main/java/net/Indyuce/mmoitems/api/crafting/ingredient/Ingredient.java index a3e43ea1..dd2c7d26 100644 --- a/src/main/java/net/Indyuce/mmoitems/api/crafting/ingredient/Ingredient.java +++ b/src/main/java/net/Indyuce/mmoitems/api/crafting/ingredient/Ingredient.java @@ -8,6 +8,7 @@ import net.Indyuce.mmoitems.api.crafting.IngredientInventory.IngredientLookupMod import net.Indyuce.mmoitems.api.crafting.IngredientInventory.PlayerIngredient; import net.Indyuce.mmoitems.api.player.RPGPlayer; import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; public abstract class Ingredient { @@ -53,7 +54,7 @@ public abstract class Ingredient { */ public abstract String formatDisplay(String string); - public abstract ItemStack generateItemStack(RPGPlayer player); + @NotNull public abstract ItemStack generateItemStack(@NotNull RPGPlayer player); public CheckedIngredient evaluateIngredient(IngredientInventory inv) { return new CheckedIngredient(this, inv.getIngredient(this, IngredientLookupMode.BASIC)); diff --git a/src/main/java/net/Indyuce/mmoitems/api/crafting/ingredient/MMOItemIngredient.java b/src/main/java/net/Indyuce/mmoitems/api/crafting/ingredient/MMOItemIngredient.java index ca590e4e..d1f0753c 100644 --- a/src/main/java/net/Indyuce/mmoitems/api/crafting/ingredient/MMOItemIngredient.java +++ b/src/main/java/net/Indyuce/mmoitems/api/crafting/ingredient/MMOItemIngredient.java @@ -11,6 +11,7 @@ import net.Indyuce.mmoitems.api.item.template.MMOItemTemplate; import net.Indyuce.mmoitems.api.player.RPGPlayer; import net.Indyuce.mmoitems.stat.data.MaterialData; import io.lumine.mythic.lib.api.MMOLineConfig; +import org.jetbrains.annotations.NotNull; public class MMOItemIngredient extends Ingredient { private final MMOItemTemplate template; @@ -52,9 +53,12 @@ public class MMOItemIngredient extends Ingredient { return string.replace("#item#", display).replace("#level#", level != 0 ? "lvl." + level + " " : "").replace("#amount#", "" + getAmount()); } + @NotNull @Override - public ItemStack generateItemStack(RPGPlayer player) { - ItemStack item = template.newBuilder(player).build().newBuilder().build(); + public ItemStack generateItemStack(@NotNull RPGPlayer player) { + + // For display, obviously + ItemStack item = template.newBuilder(player).build().newBuilder().build(true); item.setAmount(getAmount()); return item; } diff --git a/src/main/java/net/Indyuce/mmoitems/api/crafting/ingredient/VanillaIngredient.java b/src/main/java/net/Indyuce/mmoitems/api/crafting/ingredient/VanillaIngredient.java index 06817cc8..8f723a0b 100644 --- a/src/main/java/net/Indyuce/mmoitems/api/crafting/ingredient/VanillaIngredient.java +++ b/src/main/java/net/Indyuce/mmoitems/api/crafting/ingredient/VanillaIngredient.java @@ -8,6 +8,7 @@ import net.Indyuce.mmoitems.MMOUtils; import net.Indyuce.mmoitems.api.player.RPGPlayer; import org.bukkit.Material; import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; public class VanillaIngredient extends Ingredient { private final Material material; @@ -39,8 +40,9 @@ public class VanillaIngredient extends Ingredient { return string.replace("#item#", display).replace("#amount#", "" + getAmount()); } - @Override - public ItemStack generateItemStack(RPGPlayer player) { + @NotNull + @Override + public ItemStack generateItemStack(@NotNull RPGPlayer player) { NBTItem item = NBTItem.get(new ItemStack(material, getAmount())); if (displayName != null) { item.setDisplayNameComponent(LegacyComponent.parse(displayName)); diff --git a/src/main/java/net/Indyuce/mmoitems/api/item/build/ItemStackBuilder.java b/src/main/java/net/Indyuce/mmoitems/api/item/build/ItemStackBuilder.java index db0b9a14..4a87b5db 100644 --- a/src/main/java/net/Indyuce/mmoitems/api/item/build/ItemStackBuilder.java +++ b/src/main/java/net/Indyuce/mmoitems/api/item/build/ItemStackBuilder.java @@ -246,4 +246,9 @@ public class ItemStackBuilder { * @return Builds the item */ public ItemStack build() { return new DynamicLore(buildNBT()).build(); } + + /** + * @return Builds the item + */ + public ItemStack build(boolean forDisplay) { return new DynamicLore(buildNBT(forDisplay)).build(); } } diff --git a/src/main/java/net/Indyuce/mmoitems/comp/mythicmobs/crafting/MythicItemIngredient.java b/src/main/java/net/Indyuce/mmoitems/comp/mythicmobs/crafting/MythicItemIngredient.java index 7c580f92..77eddeab 100644 --- a/src/main/java/net/Indyuce/mmoitems/comp/mythicmobs/crafting/MythicItemIngredient.java +++ b/src/main/java/net/Indyuce/mmoitems/comp/mythicmobs/crafting/MythicItemIngredient.java @@ -11,6 +11,7 @@ import io.lumine.xikage.mythicmobs.items.MythicItem; import net.Indyuce.mmoitems.api.crafting.ingredient.Ingredient; import net.Indyuce.mmoitems.api.player.RPGPlayer; import io.lumine.mythic.lib.api.MMOLineConfig; +import org.jetbrains.annotations.NotNull; public class MythicItemIngredient extends Ingredient { private final MythicItem mythicitem; @@ -38,8 +39,9 @@ public class MythicItemIngredient extends Ingredient { return string.replace("#item#", display).replace("#amount#", "" + getAmount()); } - @Override - public ItemStack generateItemStack(RPGPlayer player) { + @NotNull + @Override + public ItemStack generateItemStack(@NotNull RPGPlayer player) { return BukkitAdapter.adapt(mythicitem.generateItemStack(getAmount())); } diff --git a/src/main/java/net/Indyuce/mmoitems/gui/CraftingStationPreview.java b/src/main/java/net/Indyuce/mmoitems/gui/CraftingStationPreview.java index 30842806..01537d90 100644 --- a/src/main/java/net/Indyuce/mmoitems/gui/CraftingStationPreview.java +++ b/src/main/java/net/Indyuce/mmoitems/gui/CraftingStationPreview.java @@ -3,6 +3,7 @@ package net.Indyuce.mmoitems.gui; import io.lumine.mythic.lib.MythicLib; import io.lumine.mythic.lib.api.item.NBTItem; import io.lumine.mythic.lib.api.util.LegacyComponent; +import io.lumine.mythic.lib.api.util.ui.SilentNumbers; import io.lumine.mythic.utils.adventure.text.Component; import net.Indyuce.mmoitems.MMOUtils; import net.Indyuce.mmoitems.api.crafting.ingredient.Ingredient.CheckedIngredient; @@ -41,29 +42,56 @@ public class CraftingStationPreview extends PluginInventory { @Override public Inventory getInventory() { + + // Create inventory of a nice size (5x6) Inventory inv = Bukkit.createInventory(this, 45, Message.RECIPE_PREVIEW.formatRaw(ChatColor.RESET)); ingredients.clear(); + + // Include each ingredient for (CheckedIngredient ing : recipe.getIngredients()) { + + // Amount exceeds 64? if (ing.getIngredient().getAmount() > 64) { + + // Generate new item for display ItemStack sample = ing.getIngredient().generateItemStack(playerData.getRPG()); sample.setAmount(64); + + /* + * Time to calculate the stacks and put through the crafting station space. + */ int amount = ing.getIngredient().getAmount(); - // calculate how many full stacks there are - int stacks = amount / 64; - // check for remainders - if ((stacks % 64) == 0) - // simply add the desired amount of ingredients - for (int i = 0; i < stacks; i++) + int stacks = SilentNumbers.floor(amount / 64D); + + // Add what must be added + while (amount > 0) { + + // Still too large? + if (amount > 64) { + + // Put a whole stack ingredients.add(sample.clone()); - else - // iterate stacks + 1 for the final one - for (int i = 0; i < (stacks + 1); i++) { - if (i == stacks) - sample.setAmount(amount - (stacks * 64)); + + // Subtract a whole stack + amount-= 64; + + // No longer greater than 64, :sleep: + } else { + + // Add remaining amount + sample.setAmount(amount); ingredients.add(sample.clone()); - } - } else + + // Done + amount-=amount; + + } } + + // Not greater than 64, just put it like that. + } else { + ingredients.add(ing.getIngredient().generateItemStack(playerData.getRPG())); + } } int min = (page - 1) * slots.length, max = page * slots.length; diff --git a/src/main/java/net/Indyuce/mmoitems/stat/Elements.java b/src/main/java/net/Indyuce/mmoitems/stat/Elements.java index 1b51b72e..12a8854a 100644 --- a/src/main/java/net/Indyuce/mmoitems/stat/Elements.java +++ b/src/main/java/net/Indyuce/mmoitems/stat/Elements.java @@ -3,6 +3,7 @@ package net.Indyuce.mmoitems.stat; import io.lumine.mythic.lib.api.item.ItemTag; import io.lumine.mythic.lib.api.item.SupportedNBTTagValues; import io.lumine.mythic.lib.api.util.AltChar; +import io.lumine.mythic.lib.api.util.ui.SilentNumbers; import net.Indyuce.mmoitems.MMOItems; import net.Indyuce.mmoitems.MMOUtils; import net.Indyuce.mmoitems.api.Element; @@ -12,11 +13,14 @@ import net.Indyuce.mmoitems.api.util.NumericStatFormula; import net.Indyuce.mmoitems.api.util.StatFormat; import net.Indyuce.mmoitems.gui.edition.EditionInventory; import net.Indyuce.mmoitems.gui.edition.ElementsEdition; +import net.Indyuce.mmoitems.stat.data.DoubleData; import net.Indyuce.mmoitems.stat.data.ElementListData; import net.Indyuce.mmoitems.stat.data.random.RandomElementListData; import net.Indyuce.mmoitems.stat.data.random.RandomStatData; import net.Indyuce.mmoitems.stat.data.type.StatData; +import net.Indyuce.mmoitems.stat.type.DoubleStat; import net.Indyuce.mmoitems.stat.type.ItemStat; +import net.Indyuce.mmoitems.stat.type.Previewable; import org.apache.commons.lang.Validate; import org.bukkit.ChatColor; import org.bukkit.Material; @@ -31,7 +35,7 @@ import java.util.HashMap; import java.util.List; import java.util.Optional; -public class Elements extends ItemStat { +public class Elements extends ItemStat implements Previewable { public Elements() { super("ELEMENT", Material.SLIME_BALL, "Elements", new String[] { "The elements of your item." }, new String[] { "slashing", "piercing", "blunt", "offhand", "range", "tool", "armor", "gem_stone" }); @@ -126,11 +130,11 @@ public class Elements extends ItemStat { for (Element element : elements.getDamageElements()) { String path = element.name().toLowerCase() + "-damage"; double value = elements.getDamage(element); - item.getLore().insert(path, ItemStat.translate(path).replace("#", new StatFormat("##").format(value))); } + item.getLore().insert(path, DoubleStat.formatPath(ItemStat.translate(path), true, value)); } for (Element element : elements.getDefenseElements()) { String path = element.name().toLowerCase() + "-defense"; double value = elements.getDefense(element); - item.getLore().insert(path, ItemStat.translate(path).replace("#", new StatFormat("##").format(value))); } + item.getLore().insert(path, DoubleStat.formatPath(ItemStat.translate(path), true, value)); } // Addtags item.addItemTag(getAppliedNBT(data)); @@ -219,4 +223,61 @@ public class Elements extends ItemStat { static HashMap defenseNBTpaths = null; static HashMap damageNBTpaths = null; + + @Override + public void whenPreviewed(@NotNull ItemStackBuilder item, @NotNull StatData currentData, @NotNull RandomStatData templateData) throws IllegalArgumentException { + Validate.isTrue(currentData instanceof ElementListData, "Current Data is not ElementListData"); + Validate.isTrue(templateData instanceof RandomElementListData, "Template Data is not RandomElementListData"); + + // Examine every element + for (Element element : Element.values()) { + + NumericStatFormula nsf = ((RandomElementListData) templateData).getDamage(element); + NumericStatFormula nsfDEF = ((RandomElementListData) templateData).getDefense(element); + + // Get Value + double techMinimum = nsf.calculate(0, -2.5); + double techMaximum = nsf.calculate(0, 2.5); + + // Get Value + double techMinimumDEF = nsfDEF.calculate(0, -2.5); + double techMaximumDEF = nsfDEF.calculate(0, 2.5); + + // Cancel if it its NEGATIVE and this doesn't support negative stats. + if (techMinimum < (nsf.getBase() - nsf.getMaxSpread())) { techMinimum = nsf.getBase() - nsf.getMaxSpread(); } + if (techMaximum > (nsf.getBase() + nsf.getMaxSpread())) { techMaximum = nsf.getBase() + nsf.getMaxSpread(); } + + if (techMinimumDEF < (nsfDEF.getBase() - nsfDEF.getMaxSpread())) { techMinimumDEF = nsfDEF.getBase() - nsfDEF.getMaxSpread(); } + if (techMaximumDEF > (nsfDEF.getBase() + nsfDEF.getMaxSpread())) { techMaximumDEF = nsfDEF.getBase() + nsfDEF.getMaxSpread(); } + + // Display if not ZERO + if (techMinimum != 0 || techMaximum != 0) { + + // Get path + String path = element.name().toLowerCase() + "-damage"; + + String builtRange; + if (SilentNumbers.round(techMinimum, 2) == SilentNumbers.round(techMaximum, 2)) { builtRange = DoubleStat.formatPath(ItemStat.translate(path), true, techMinimum); } + else { builtRange = DoubleStat.formatPath(ItemStat.translate(path), true, techMinimum, techMaximum); } + + // Just display normally + item.getLore().insert(path, builtRange); } + + // Display if not ZERO + if (techMinimumDEF != 0 || techMaximumDEF != 0) { + + // Get path + String path = element.name().toLowerCase() + "-defense"; + + String builtRange; + if (SilentNumbers.round(techMinimumDEF, 2) == SilentNumbers.round(techMaximumDEF, 2)) { builtRange = DoubleStat.formatPath(ItemStat.translate(path), true, techMinimumDEF); } + else { builtRange = DoubleStat.formatPath(ItemStat.translate(path), true, techMinimumDEF, techMaximumDEF); } + + // Just display normally + item.getLore().insert(path, builtRange); } + } + + // Addtags + item.addItemTag(getAppliedNBT(currentData)); + } } diff --git a/src/main/java/net/Indyuce/mmoitems/stat/data/random/RandomElementListData.java b/src/main/java/net/Indyuce/mmoitems/stat/data/random/RandomElementListData.java index e0207d33..46c411d5 100644 --- a/src/main/java/net/Indyuce/mmoitems/stat/data/random/RandomElementListData.java +++ b/src/main/java/net/Indyuce/mmoitems/stat/data/random/RandomElementListData.java @@ -12,6 +12,7 @@ import net.Indyuce.mmoitems.api.item.build.MMOItemBuilder; import net.Indyuce.mmoitems.api.util.NumericStatFormula; import net.Indyuce.mmoitems.stat.data.ElementListData; import net.Indyuce.mmoitems.stat.data.type.StatData; +import org.jetbrains.annotations.NotNull; public class RandomElementListData implements StatData, RandomStatData { private final Map damage = new HashMap<>(), defense = new HashMap<>(); @@ -36,13 +37,8 @@ public class RandomElementListData implements StatData, RandomStatData { return defense.containsKey(element); } - public NumericStatFormula getDefense(Element element) { - return defense.getOrDefault(element, NumericStatFormula.ZERO); - } - - public NumericStatFormula getDamage(Element element) { - return damage.getOrDefault(element, NumericStatFormula.ZERO); - } + @NotNull public NumericStatFormula getDefense(@NotNull Element element) { return defense.getOrDefault(element, NumericStatFormula.ZERO); } + @NotNull public NumericStatFormula getDamage(@NotNull Element element) { return damage.getOrDefault(element, NumericStatFormula.ZERO); } public Set getDefenseElements() { return defense.keySet(); diff --git a/src/main/java/net/Indyuce/mmoitems/stat/type/DoubleStat.java b/src/main/java/net/Indyuce/mmoitems/stat/type/DoubleStat.java index 53cf2219..6d766fc2 100644 --- a/src/main/java/net/Indyuce/mmoitems/stat/type/DoubleStat.java +++ b/src/main/java/net/Indyuce/mmoitems/stat/type/DoubleStat.java @@ -34,6 +34,7 @@ import org.jetbrains.annotations.Nullable; import java.text.DecimalFormat; import java.util.ArrayList; import java.util.List; +import java.util.Objects; import java.util.Optional; import java.util.regex.Pattern; @@ -97,31 +98,62 @@ public class DoubleStat extends ItemStat implements Upgradable, Previewable { DoubleData uData = (DoubleData) hist.recalculateUnupgraded(); // Calculate Difference - upgradeShift = value - uData.getValue(); - } - - } + upgradeShift = value - uData.getValue(); } } // Display if not ZERO if (value != 0 || upgradeShift != 0) { + // Get path and modify + String pathFormat = MMOItems.plugin.getLanguage().getStatFormat(getPath()); + // Displaying upgrades? if (upgradeShift != 0) { - item.getLore().insert(getPath(), formatNumericStat(value, "#", new StatFormat("##").format(value)) + item.getLore().insert(getPath(), formatPath(MMOItems.plugin.getLanguage().getStatFormat(getPath()), moreIsBetter(), value) + + // Add upgrade format + MythicLib.plugin.parseColors(UpgradeTemplate.getUpgradeChangeSuffix(plus(upgradeShift) + (new StatFormat("##").format(upgradeShift)), !isGood(upgradeShift)))); } else { // Just display normally - item.getLore().insert(getPath(), formatNumericStat(value, "#", new StatFormat("##").format(value))); - } - } + item.getLore().insert(getPath(), formatPath(MMOItems.plugin.getLanguage().getStatFormat(getPath()), moreIsBetter(), value)); + + } } // Add NBT Path item.addItemTag(getAppliedNBT(data)); } + @NotNull public static String formatPath(@NotNull String format, boolean moreIsBetter, double value) { + + // Thats it + return format + + // Replace conditional pluses with +value + .replace("#",getColorPrefix(value < 0 && moreIsBetter) + (value > 0 ? "+" : "") + new StatFormat("##").format(value)) + + // Replace loose pounds with the value + .replace("#",getColorPrefix(value < 0 && moreIsBetter) + new StatFormat("##").format(value)) + + // Replace loose es + .replace("", (value > 0 ? "+" : "")); + } + + @NotNull public static String formatPath(@NotNull String format, boolean moreIsBetter, double min, double max) { + + // Thats it + return format + + // Replace conditional pluses with +value + .replace("","") + + // Replace loose pounds with the value + .replace("#", getColorPrefix(min < 0 && moreIsBetter) + + (min > 0 ? "+" : "") + new StatFormat("##").format(min) + + MMOItems.plugin.getConfig().getString("stats-displaying.range-dash", "\u00a7f\u00a7l⎓") + getColorPrefix(max < 0 && moreIsBetter) + + (min < 0 && max > 0 ? "+" : "") + new StatFormat("##").format(max)); } + @Override public void whenPreviewed(@NotNull ItemStackBuilder item, @NotNull StatData currentData, @NotNull RandomStatData templateData) throws IllegalArgumentException { Validate.isTrue(currentData instanceof DoubleData, "Current Data is not Double Data"); @@ -144,12 +176,25 @@ public class DoubleStat extends ItemStat implements Upgradable, Previewable { if (techMinimum != 0 || techMaximum != 0) { String builtRange; - if (SilentNumbers.round(techMinimum, 2) == SilentNumbers.round(techMaximum, 2)) { builtRange = new StatFormat("##").format(techMinimum); } - else { builtRange = new StatFormat("##").format(techMinimum) + "-" + new StatFormat("##").format(techMaximum); } + if (SilentNumbers.round(techMinimum, 2) == SilentNumbers.round(techMaximum, 2)) { + builtRange = formatPath(MMOItems.plugin.getLanguage().getStatFormat(getPath()), moreIsBetter(), techMaximum); + + } else { + builtRange = formatPath(MMOItems.plugin.getLanguage().getStatFormat(getPath()), moreIsBetter(), techMinimum, techMaximum); } // Just display normally - item.getLore().insert(getPath(), formatNumericStat(techMinimum, "#", builtRange)); - } + item.getLore().insert(getPath(), builtRange); } + } + + + @NotNull public static String getColorPrefix(boolean isNegative) { + + // Get the base + if (isNegative) { + return Objects.requireNonNull(MMOItems.plugin.getConfig().getString("stats-displaying.color-negative", "")); + + } else { + return Objects.requireNonNull(MMOItems.plugin.getConfig().getString("stats-displaying.color-positive", "")); } } @NotNull String plus(double amount) { if (amount >= 0) { return "+"; } else return ""; } diff --git a/src/main/java/net/Indyuce/mmoitems/stat/type/ItemStat.java b/src/main/java/net/Indyuce/mmoitems/stat/type/ItemStat.java index cdc52122..bf491fbe 100644 --- a/src/main/java/net/Indyuce/mmoitems/stat/type/ItemStat.java +++ b/src/main/java/net/Indyuce/mmoitems/stat/type/ItemStat.java @@ -220,8 +220,7 @@ public abstract class ItemStat { public String formatNumericStat(double value, String... replace) { String format = MMOItems.plugin.getLanguage().getStatFormat(getPath()).replace("", value > 0 ? "+" : ""); - for (int j = 0; j < replace.length; j += 2) - format = format.replace(replace[j], replace[j + 1]); + for (int j = 0; j < replace.length; j += 2) { format = format.replace(replace[j], replace[j + 1]); } return format; } diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index c0a6416e..4a9cf9ad 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -91,6 +91,13 @@ item-upgrading: stat-change-positive: '&a' stat-change-negative: '&c' +stats-displaying: + + # This will be a prefix to numeric stats, + # changing their color when they are undesirable. + color-positive: '' + color-negative: '' + soulbound: # Edit soulbound damage when players try to use