- RevID increase no longer repairs items forcibly

+ Config option to automatically regenerate gems when they are popped out from their socket by a RevID update
+ Allows multiple set bonuses to be equipped at the same time
+ Allows granted-permissions stat in set bonuses
+ keepTiers config option for RevID updates
+ API for death downgrade stat
This commit is contained in:
Gunging 2022-05-10 15:31:38 -05:00
parent 7c68dce1f7
commit 2e204a8fc6
10 changed files with 511 additions and 193 deletions

View File

@ -1,11 +1,6 @@
package net.Indyuce.mmoitems.api;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.*;
import org.apache.commons.lang.Validate;
import org.bukkit.configuration.ConfigurationSection;
@ -17,6 +12,7 @@ import net.Indyuce.mmoitems.MMOUtils;
import net.Indyuce.mmoitems.stat.data.AbilityData;
import net.Indyuce.mmoitems.stat.data.ParticleData;
import net.Indyuce.mmoitems.stat.type.ItemStat;
import org.jetbrains.annotations.NotNull;
public class ItemSet {
private final Map<Integer, SetBonuses> bonuses = new HashMap<>();
@ -39,10 +35,14 @@ public class ItemSet {
Validate.isTrue(config.contains("bonuses"), "Could not find item set bonuses");
for (int j = 2; j <= itemLimit; j++)
if (config.getConfigurationSection("bonuses").contains("" + j)) {
if (config.getConfigurationSection("bonuses").contains(String.valueOf(j))) {
SetBonuses bonuses = new SetBonuses();
for (String key : config.getConfigurationSection("bonuses." + j).getKeys(false))
// Add permissions
for (String perm : config.getConfigurationSection("bonuses." + j).getStringList("granted-permissions")) { bonuses.addPermission(perm); }
for (String key : config.getConfigurationSection("bonuses." + j).getKeys(false)) {
try {
String format = key.toUpperCase().replace("-", "_").replace(" ", "_");
@ -75,6 +75,7 @@ public class ItemSet {
} catch (IllegalArgumentException exception) {
throw new IllegalArgumentException("Could not load set bonus '" + key + "': " + exception.getMessage());
}
}
this.bonuses.put(j, bonuses);
}
@ -105,6 +106,7 @@ public class ItemSet {
private final Map<PotionEffectType, PotionEffect> permEffects = new HashMap<>();
private final Set<AbilityData> abilities = new HashSet<>();
private final Set<ParticleData> particles = new HashSet<>();
private final ArrayList<String> permissions = new ArrayList<>();
public void addStat(ItemStat stat, double value) {
stats.put(stat, value);
@ -122,6 +124,8 @@ public class ItemSet {
particles.add(particle);
}
public void addPermission(@NotNull String permission) { permissions.add(permission); }
public boolean hasStat(ItemStat stat) {
return stats.containsKey(stat);
}
@ -146,6 +150,8 @@ public class ItemSet {
return abilities;
}
@NotNull public ArrayList<String> getPermissions() { return permissions; }
public void merge(SetBonuses bonuses) {
bonuses.getStats().forEach((stat, value) -> stats.put(stat, (stats.containsKey(stat) ? stats.get(stat) : 0) + value));
@ -154,6 +160,8 @@ public class ItemSet {
permEffects.put(effect.getType(), effect);
abilities.addAll(bonuses.getAbilities());
permissions.addAll(bonuses.getPermissions());
}
}
}

View File

@ -1,8 +1,10 @@
package net.Indyuce.mmoitems.api;
import net.Indyuce.mmoitems.api.util.MMOItemReforger;
import org.bukkit.ChatColor;
import org.bukkit.configuration.ConfigurationSection;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
@ -19,6 +21,7 @@ public class ReforgeOptions {
private final boolean keepSoulbind;
private final boolean keepExternalSH;
private final boolean keepModifications;
@Nullable private final Boolean keepTier;
private final boolean reroll;
@ -78,6 +81,7 @@ public class ReforgeOptions {
keepModifications = config.getBoolean("modifications");
reroll = config.getBoolean("reroll");
keepAdvancedEnchantments = config.getBoolean("advanced-enchantments");
keepTier = config.contains("tier") ? config.getBoolean("tier", true) : null;
}
public ReforgeOptions(boolean... values) {
@ -92,6 +96,7 @@ public class ReforgeOptions {
keepModifications = arr(values, 8);
keepAdvancedEnchantments = arr(values, 9);
keepSkins = arr(values, 10);
keepTier = arr(values, 11);
}
boolean arr(@NotNull boolean[] booleans, int idx) {
@ -104,70 +109,56 @@ public class ReforgeOptions {
/**
* Keeps the display name of the item.
*/
public boolean shouldReroll() {
return reroll;
}
public boolean shouldReroll() { return reroll; }
/**
* Keeps the display name of the item.
*/
public boolean shouldKeepName() {
return keepName;
}
public boolean shouldKeepName() { return keepName; }
/**
* Keeps the modifiers of the item.
*/
public boolean shouldKeepMods() {
return keepModifications;
}
public boolean shouldKeepMods() { return keepModifications; }
/**
* Keeps all lore lines that begin with {@link org.bukkit.ChatColor#GRAY}
*/
public boolean shouldKeepLore() {
return keepLore;
}
public boolean shouldKeepLore() { return keepLore; }
/**
* Keeps skins
*/
public boolean shouldKeepSkins() {
return keepSkins;
public boolean shouldKeepSkins() { return keepSkins; }
}
/**
* Should keep the tier? defaults to {@link MMOItemReforger#keepTiersWhenReroll}
*/
public boolean shouldKeepTier() { return keepTier == null ? MMOItemReforger.keepTiersWhenReroll : keepTier; }
/**
* Should this keep the enchantments the player
* manually cast onto this item? (Not from gem
* stones nor upgrades).
*/
public boolean shouldKeepEnchantments() {
return keepEnchantments;
}
public boolean shouldKeepEnchantments() { return keepEnchantments; }
/**
* Should this keep the enchantments the player
* manually cast onto this item? (Not from gem
* stones nor upgrades).
*/
public boolean shouldKeepAdvancedEnchants() {
return keepAdvancedEnchantments;
}
public boolean shouldKeepAdvancedEnchants() { return keepAdvancedEnchantments; }
/**
* Keep 'extraneous' data registered onto the Stat History
*/
public boolean shouldKeepExternalSH() {
return keepExternalSH;
}
public boolean shouldKeepExternalSH() { return keepExternalSH; }
/**
* Retains the upgrade level of the item.
*/
public boolean shouldKeepUpgrades() {
return keepUpgrades;
}
public boolean shouldKeepUpgrades() { return keepUpgrades; }
/**
* Retains all gem stones if there are any, removing
@ -175,14 +166,10 @@ public class ReforgeOptions {
* <p></p>
* Gemstones remember at what upgrade level they were inserted.
*/
public boolean shouldKeepGemStones() {
return keepGemStones;
}
public boolean shouldKeepGemStones() { return keepGemStones; }
/**
* Retains the soulbind if it has any.
*/
public boolean shouldKeepSoulbind() {
return keepSoulbind;
}
public boolean shouldKeepSoulbind() { return keepSoulbind; }
}

View File

@ -1,23 +1,25 @@
package net.Indyuce.mmoitems.api.item.mmoitem;
import io.lumine.mythic.lib.api.item.NBTItem;
import io.lumine.mythic.lib.api.util.ui.SilentNumbers;
import net.Indyuce.mmoitems.ItemStats;
import net.Indyuce.mmoitems.MMOItems;
import net.Indyuce.mmoitems.api.ItemTier;
import net.Indyuce.mmoitems.api.Type;
import net.Indyuce.mmoitems.api.UpgradeTemplate;
import net.Indyuce.mmoitems.api.interaction.util.DurabilityItem;
import net.Indyuce.mmoitems.api.item.ItemReference;
import net.Indyuce.mmoitems.api.item.build.ItemStackBuilder;
import net.Indyuce.mmoitems.api.util.MMOItemReforger;
import net.Indyuce.mmoitems.stat.Enchants;
import net.Indyuce.mmoitems.stat.data.DoubleData;
import net.Indyuce.mmoitems.stat.data.GemSocketsData;
import net.Indyuce.mmoitems.stat.data.GemstoneData;
import net.Indyuce.mmoitems.stat.data.UpgradeData;
import net.Indyuce.mmoitems.stat.data.*;
import net.Indyuce.mmoitems.stat.data.type.Mergeable;
import net.Indyuce.mmoitems.stat.data.type.StatData;
import net.Indyuce.mmoitems.stat.type.ItemStat;
import net.Indyuce.mmoitems.stat.type.StatHistory;
import org.apache.commons.lang.Validate;
import org.bukkit.Material;
import org.bukkit.inventory.meta.ItemMeta;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@ -225,11 +227,25 @@ public class MMOItem implements ItemReference {
*/
public int getDamage() {
if (!hasData(ItemStats.ITEM_DAMAGE)) { return 0; }
// Does it use MMO Durability?
int maxDurability = hasData(ItemStats.MAX_DURABILITY) ? SilentNumbers.round(((DoubleData) getData(ItemStats.MAX_DURABILITY)).getValue()) : -1;
DoubleData durData = (DoubleData) getData(ItemStats.ITEM_DAMAGE);
if (maxDurability > 0) {
return SilentNumbers.round(durData.getValue());
// Apparently we must do this
NBTItem nbtItem = newBuilder().buildNBT();
// Durability
int durability = hasData(ItemStats.CUSTOM_DURABILITY) ? SilentNumbers.round(((DoubleData) getData(ItemStats.CUSTOM_DURABILITY)).getValue()) : maxDurability;
// Damage is the difference between max and current durability
return maxDurability - durability;
} else {
// Use vanilla durability
return hasData(ItemStats.ITEM_DAMAGE) ? SilentNumbers.round(((DoubleData) getData(ItemStats.ITEM_DAMAGE)).getValue()) : 0;
}
}
/**
@ -240,9 +256,33 @@ public class MMOItem implements ItemReference {
*/
public void setDamage(int damage) {
// Too powerful
if (hasData(ItemStats.UNBREAKABLE)) { return; }
setData(ItemStats.ITEM_DAMAGE, new DoubleData(damage));
// Does it use MMO Durability?
int maxDurability = hasData(ItemStats.MAX_DURABILITY) ? SilentNumbers.round(((DoubleData) getData(ItemStats.MAX_DURABILITY)).getValue()) : -1;
if (maxDurability > 0) {
// Apparently we must do this
NBTItem nbtItem = newBuilder().buildNBT();
// Durability
setData(ItemStats.CUSTOM_DURABILITY, new DoubleData(maxDurability - damage));
// Scale damage
Material mat = hasData(ItemStats.MATERIAL) ? ((MaterialData) getData(ItemStats.MATERIAL)).getMaterial() : Material.GOLD_INGOT;
double multiplier = ((double) damage) * ((double) mat.getMaxDurability()) / ((double) maxDurability);
if (multiplier == 0) { return; }
// Set to some decent amount of damage
setData(ItemStats.ITEM_DAMAGE, new DoubleData(multiplier));
} else {
// Use vanilla durability
setData(ItemStats.ITEM_DAMAGE, new DoubleData(damage));
}
}
//endregion
@ -373,6 +413,9 @@ public class MMOItem implements ItemReference {
}
//XTC//MMOItems.log("\u00a7b *\u00a77 Regen Size:\u00a79 " + regeneratedGems.values().size());
// If RevID updating, it basically just regenerates
if (MMOItemReforger.gemstonesRevIDWhenUnsocket) { return new ArrayList<>(regeneratedGems.values()); }
// Identify actual attributes
for (ItemStat stat : getStats()) {
@ -421,6 +464,8 @@ public class MMOItem implements ItemReference {
// Can we generate?
MMOItem restored = MMOItems.plugin.getMMOItem(MMOItems.plugin.getTypes().get(gem.getMMOItemType()), gem.getMMOItemID());
if (MMOItemReforger.gemstonesRevIDWhenUnsocket) { return restored; }
// Valid? neat-o
if (restored != null) {
//XTC//MMOItems.log("\u00a7a *\u00a73>\u00a77 Valid, regenerated \u00a7e" + restored.getData(ItemStats.NAME));

View File

@ -4,6 +4,7 @@ import io.lumine.mythic.lib.MythicLib;
import io.lumine.mythic.lib.api.item.NBTItem;
import io.lumine.mythic.lib.api.player.EquipmentSlot;
import io.lumine.mythic.lib.api.player.MMOPlayerData;
import io.lumine.mythic.lib.api.util.ui.SilentNumbers;
import io.lumine.mythic.lib.damage.AttackMetadata;
import io.lumine.mythic.lib.player.PlayerMetadata;
import io.lumine.mythic.lib.player.modifier.ModifierSource;
@ -19,6 +20,7 @@ import net.Indyuce.mmoitems.api.crafting.CraftingStatus;
import net.Indyuce.mmoitems.api.event.RefreshInventoryEvent;
import net.Indyuce.mmoitems.api.interaction.Tool;
import net.Indyuce.mmoitems.api.item.ItemReference;
import net.Indyuce.mmoitems.api.item.mmoitem.MMOItem;
import net.Indyuce.mmoitems.api.item.mmoitem.VolatileMMOItem;
import net.Indyuce.mmoitems.api.player.inventory.EquippedItem;
import net.Indyuce.mmoitems.api.player.inventory.EquippedPlayerItem;
@ -61,6 +63,7 @@ public class PlayerData {
private final Set<ParticleRunnable> itemParticles = new HashSet<>();
private ParticleRunnable overridingItemParticles = null;
private boolean fullHands = false;
@Nullable
private SetBonuses setBonuses = null;
private final PlayerStats stats;
@ -174,10 +177,7 @@ public class PlayerData {
overridingItemParticles = null;
if (MMOItems.plugin.hasPermissions()) {
Permission perms = MMOItems.plugin.getVault().getPermissions();
permissions.forEach(perm -> {
if (perms.has(getPlayer(), perm))
perms.playerRemove(getPlayer(), perm);
});
permissions.forEach(perm -> { if (perms.has(getPlayer(), perm)) { perms.playerRemove(getPlayer(), perm); } });
}
permissions.clear();
@ -248,12 +248,10 @@ public class PlayerData {
* Apply permissions if vault exists
*/
if (MMOItems.plugin.hasPermissions() && item.hasData(ItemStats.GRANTED_PERMISSIONS)) {
permissions.addAll(((StringListData) item.getData(ItemStats.GRANTED_PERMISSIONS)).getList());
Permission perms = MMOItems.plugin.getVault().getPermissions();
permissions.forEach(perm -> {
if (!perms.has(getPlayer(), perm))
perms.playerAdd(getPlayer(), perm);
});
permissions.forEach(perm -> { if (!perms.has(getPlayer(), perm)) { perms.playerAdd(getPlayer(), perm); } });
}
}
@ -261,8 +259,6 @@ public class PlayerData {
* calculate the player's item set and add the bonus permanent effects /
* bonus abilities to the playerdata maps
*/
int max = 0;
ItemSet set = null;
Map<ItemSet, Integer> sets = new HashMap<>();
for (EquippedPlayerItem equipped : inventory.getEquipped()) {
VolatileMMOItem item = equipped.getItem();
@ -273,14 +269,28 @@ public class PlayerData {
int nextInt = (sets.getOrDefault(itemSet, 0)) + 1;
sets.put(itemSet, nextInt);
if (nextInt >= max) {
max = nextInt;
set = itemSet;
}
// Reset
setBonuses = null;
for (Map.Entry<ItemSet,Integer> equippedSetBonus : sets.entrySet()) {
if (setBonuses == null) {
// Set set bonuses
setBonuses = equippedSetBonus.getKey().getBonuses(equippedSetBonus.getValue());
} else {
// Merge bonuses
setBonuses.merge(equippedSetBonus.getKey().getBonuses(equippedSetBonus.getValue()));
}
}
setBonuses = set == null ? null : set.getBonuses(max);
if (hasSetBonuses()) {
if (setBonuses != null) {
Permission perms = MMOItems.plugin.getVault().getPermissions();
for (String perm : setBonuses.getPermissions())
if (!perms.has(getPlayer(), perm)) { perms.playerAdd(getPlayer(), perm); }
for (AbilityData ability : setBonuses.getAbilities())
mmoData.getPassiveSkillMap().addModifier(new PassiveSkill("MMOItemsItem", ability, EquipmentSlot.OTHER, ModifierSource.OTHER));
for (ParticleData particle : setBonuses.getParticles())

View File

@ -0,0 +1,340 @@
package net.Indyuce.mmoitems.api.util;
import io.lumine.mythic.lib.api.item.NBTItem;
import io.lumine.mythic.lib.api.util.ui.SilentNumbers;
import net.Indyuce.mmoitems.ItemStats;
import net.Indyuce.mmoitems.api.interaction.util.DurabilityItem;
import net.Indyuce.mmoitems.api.item.mmoitem.LiveMMOItem;
import net.Indyuce.mmoitems.api.item.mmoitem.MMOItem;
import net.Indyuce.mmoitems.api.item.mmoitem.VolatileMMOItem;
import net.Indyuce.mmoitems.api.player.PlayerData;
import net.Indyuce.mmoitems.api.player.inventory.EditableEquippedItem;
import net.Indyuce.mmoitems.api.player.inventory.EquippedPlayerItem;
import net.Indyuce.mmoitems.api.player.inventory.InventoryUpdateHandler;
import net.Indyuce.mmoitems.api.util.message.Message;
import net.Indyuce.mmoitems.stat.data.UpgradeData;
import net.Indyuce.mmoitems.stat.type.NameData;
import org.bukkit.ChatColor;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Random;
public class DeathDowngrading {
/**
* This will go through the following steps:
*
* #1 Evaluate the list of equipped items {@link InventoryUpdateHandler#getEquipped()} to
* find those that can be death-downgraded.
*
*
* #2 Roll for death downgrade chances, downgrading the items
*
* @param player Player whose inventory is to be death-downgraded.
*/
public static void playerDeathDowngrade(@NotNull Player player) {
// Get Player
PlayerData data = PlayerData.get(player);
// Get total downgrade chance, anything less than zero is invalid
double deathChance = data.getStats().getStat(ItemStats.DOWNGRADE_ON_DEATH_CHANCE);
//DET//MMOItems.log("\u00a78DETH \u00a7cDG\u00a77 Current chance:\u00a7b " + deathChance);
if (deathChance <= 0) { return; }
// Make sure the equipped items list is up to date and retrieve it
data.updateInventory();
List<EquippedPlayerItem> items = data.getInventory().getEquipped();
ArrayList<EditableEquippedItem> equipped = new ArrayList<>();
// Equipped Player Items yeah...
for (EquippedPlayerItem playerItem : items) {
// Cannot downgrade? skip
if (!canDeathDowngrade(playerItem)) { continue; }
// Okay explore stat
equipped.add((EditableEquippedItem) playerItem.getEquipped());
//DET//MMOItems.log("\u00a78DETH \u00a7cDG\u00a77 Yes. \u00a7aAccepted");
}
// Nothing to perform operations? Snooze
if (equipped.size() == 0) {
//DET//MMOItems.log("\u00a78DETH \u00a7cDG\u00a77 No items to downgrade. ");
return; }
// Create random
Random random = new Random();
// Degrade those items!
while (deathChance >= 100 && equipped.size() > 0) {
// Decrease
deathChance -= 100;
// Downgrade random item
int deathChosen = random.nextInt(equipped.size());
/*
* The item was chosen, we must downgrade it by one level.
*/
EditableEquippedItem equip = equipped.get(deathChosen);
// Downgrade and remove from list
equip.setItem(downgrade(new LiveMMOItem(equip.getItem()), player));
equipped.remove(deathChosen);
//DET//MMOItems.log("\u00a78DETH \u00a7cDG\u00a77 Autodegrading\u00a7a " + mmo.getData(ItemStats.NAME));
}
// If there is chance, and there is size, and there is chance success
if (deathChance > 0 && equipped.size() > 0 && random.nextInt(100) < deathChance) {
// Downgrade random item
int d = random.nextInt(equipped.size());
/*
* The item was chosen, we must downgrade it by one level.
*/
EditableEquippedItem equip = equipped.get(d);
// Downgrade and remove from list
equip.setItem(downgrade(new LiveMMOItem(equip.getItem()), player));
equipped.remove(d);
//DET//MMOItems.log("\u00a78DETH \u00a7cDG\u00a77 Chancedegrade\u00a7a " + mmo.getData(ItemStats.NAME));
}
}
/**
* @param allItems Absolutely all the items equipped by the player. This method will only affect
* those that (A) can be downgraded, and (B) RNG roll to be downgraded.
*
* @param player Player whose items are being downgraded.
*
* @param deathChance Chance of downgrading one item of the list. Overrollable.
*
* @return The same list of items... but some of them possibly downgraded.
*/
@NotNull ArrayList<ItemStack> downgradeItems(@NotNull List<ItemStack> allItems, @NotNull Player player, double deathChance) {
// List of result and downgrade
ArrayList<ItemStack> result = new ArrayList<>();
ArrayList<ItemStack> downgrade = new ArrayList<>();
// Choose
for (ItemStack item : allItems) {
// ?? Not that
if (SilentNumbers.isAir(item)) { continue; }
// Downgrade yay or nay
if (canDeathDowngrade(item)) {
// On to downgrading
downgrade.add(item);
} else {
// On to result
result.add(item);
}
}
// Create random
Random random = new Random();
// Degrade those items!
while (deathChance >= 100 && downgrade.size() > 0) {
// Decrease
deathChance -= 100;
// Downgrade random item
int deathChosen = random.nextInt(downgrade.size());
/*
* The item was chosen, we must downgrade it by one level.
*/
ItemStack equip = downgrade.get(deathChosen);
// Downgrade and remove from list
result.add(downgrade(new LiveMMOItem(equip), player));
// Remove this one item
downgrade.remove(deathChosen);
}
// If there is chance, and there is size, and there is chance success
if (deathChance > 0 && downgrade.size() > 0 && random.nextInt(100) < deathChance) {
// Downgrade random item
int deathChosen = random.nextInt(downgrade.size());
/*
* The item was chosen, we must downgrade it by one level.
*/
ItemStack equip = downgrade.get(deathChosen);
// Downgrade and remove from list
result.add(downgrade(new LiveMMOItem(equip), player));
// Remove this one item
downgrade.remove(deathChosen);
}
// Those that survived are rejoined
result.addAll(downgrade);
// That's it
return result;
}
/**
* @param player For some reason I myself dont understand, {@link DurabilityItem} wants
* a non-null player to be able to perform durability operations.
*
* @param item Item to downgrade, make sure to have checked
* {@link #canDeathDowngrade(ItemStack)} before!
*
* @return This item but downgraded if it was possible.
*/
@NotNull public static ItemStack downgrade(@NotNull ItemStack item, @NotNull Player player) {
// No Item Meta I sleep
if (SilentNumbers.isAir(item) || !item.getType().isItem()) { return item; }
// Must be a MMOItem
NBTItem asNBT = NBTItem.get(item);
if (!asNBT.hasType()) { return item; }
// Delegate to MMOItem Method
return downgrade(new LiveMMOItem(asNBT), player);
}
/**
* @param player For some reason I myself dont understand, {@link DurabilityItem} wants
* a non-null player to be able to perform durability operations.
*
* @param mmo Item to downgrade, make sure to have checked
* {@link #canDeathDowngrade(MMOItem)} before!
*
* @return This item but downgraded if it was possible.
*/
@NotNull public static ItemStack downgrade(@NotNull LiveMMOItem mmo, @NotNull Player player) {
mmo.getUpgradeTemplate().upgradeTo(mmo, mmo.getUpgradeLevel() - 1);
// Build NBT
ItemStack bakedItem = mmo.newBuilder().build();
// Set durability to zero (full repair)
DurabilityItem dur = new DurabilityItem(player, mmo.newBuilder().buildNBT());
// Perform durability operations
if (dur.getDurability() != dur.getMaxDurability()) {
dur.addDurability(dur.getMaxDurability());
bakedItem.setItemMeta(dur.toItem().getItemMeta());}
// Send downgrading message
Message.DEATH_DOWNGRADING.format(ChatColor.RED, "#item#", (mmo.getData(ItemStats.NAME) instanceof NameData) ? mmo.getData(ItemStats.NAME).toString() : SilentNumbers.getItemName(bakedItem, false))
.send(player);
// Uuuuh
return bakedItem;
}
/**
* @param player Player to check their death downgrade chance
*
* @return The death downgrade chance of the player
*/
public double getDeathDowngradeChance(@NotNull Player player) {
// Get Player
PlayerData data = PlayerData.get(player);
// Get total downgrade chance, anything less than zero is invalid
return data.getStats().getStat(ItemStats.DOWNGRADE_ON_DEATH_CHANCE);
}
/**
* @param playerItem Equipped Item you want to know if it can be death downgraded
*
* @return If this is an instance of {@link EditableEquippedItem} and meets {@link #canDeathDowngrade(MMOItem)}
*/
@Contract("null->false")
public static boolean canDeathDowngrade(@Nullable EquippedPlayerItem playerItem) {
// Null
if (playerItem == null) { return false; }
//DET//playerItem.getItem().hasData(ItemStats.NAME);
//DET//MMOItems.log("\u00a78DETH \u00a7cDG\u00a77 Item:\u00a7b " + playerItem.getItem().getData(ItemStats.NAME));
// Cannot perform operations of items that are uneditable
if (!(playerItem.getEquipped() instanceof EditableEquippedItem)) {
//DET//MMOItems.log("\u00a78DETH \u00a7cDG\u00a77 Not equippable. \u00a7cCancel");
return false; }
// Delegate to MMOItem Method
return canDeathDowngrade(playerItem.getItem());
}
/**
* @param playerItem Item you want to know if it can be death downgraded
*
* @return If this item is an MMOItem and meets {@link #canDeathDowngrade(MMOItem)}
*/
@Contract("null->false")
public static boolean canDeathDowngrade(@Nullable ItemStack playerItem) {
// Null
if (SilentNumbers.isAir(playerItem) || !playerItem.getType().isItem()) { return false; }
//DET//playerItem.getItem().hasData(ItemStats.NAME);
//DET//MMOItems.log("\u00a78DETH \u00a7cDG\u00a77 Item:\u00a7b " + playerItem.getItem().getData(ItemStats.NAME));
// Get NBT
NBTItem asNBT = NBTItem.get(playerItem);
if (!asNBT.hasType()) { return false; }
// Delegate to MMOItem Method
return canDeathDowngrade(new VolatileMMOItem(asNBT));
}
/**
* @param playerItem MMOItem you want to know if it can be death downgraded
*
* @return If this item has {@link ItemStats#DOWNGRADE_ON_DEATH} enabled, and
* has an upgrade template, and hasnt reached its minimum upgrades.
*/
@Contract("null->false")
public static boolean canDeathDowngrade(@Nullable MMOItem playerItem) {
if (playerItem == null) { return false; }
// Not downgradeable on death? Snooze
if (!playerItem.hasData(ItemStats.DOWNGRADE_ON_DEATH)) {
//DET//MMOItems.log("\u00a78DETH \u00a7cDG\u00a77 Not Downgradeable. \u00a7cCancel");
return false; }
// No upgrade template no snooze
if(!playerItem.hasData(ItemStats.UPGRADE)) {
//DET//MMOItems.log("\u00a78DETH \u00a7cDG\u00a77 Not Upgradeable. \u00a7cCancel");
return false; }
if (!playerItem.hasUpgradeTemplate()) {
//DET//MMOItems.log("\u00a78DETH \u00a7cDG\u00a77 Null Template. \u00a7cCancel");
return false; }
// If it can be downgraded by one level...
UpgradeData upgradeData = (UpgradeData) playerItem.getData(ItemStats.UPGRADE);
//DET//MMOItems.log("\u00a78DETH \u00a7cDG\u00a77 Too downgraded? \u00a7c" + (upgradeData.getLevel() <= upgradeData.getMin()));
return upgradeData.getLevel() > upgradeData.getMin();
}
}

View File

@ -412,11 +412,13 @@ public class MMOItemReforger {
: iLevel;
// Identify tier.
ItemTier tier =
// Does the item have a tier, and it should keep it?
(MMOItemReforger.keepTiersWhenReroll && getOldMMOItem().hasData(ItemStats.TIER)) ?
(options.shouldKeepTier() && getOldMMOItem().hasData(ItemStats.TIER)) ?
// The tier will be the current tier
MMOItems.plugin.getTiers().get(getOldMMOItem().getData(ItemStats.TIER).toString())
@ -478,11 +480,13 @@ public class MMOItemReforger {
public static int autoSoulbindLevel = 1;
public static int defaultItemLevel = -32767;
public static boolean keepTiersWhenReroll = true;
public static boolean gemstonesRevIDWhenUnsocket = false;
public static void reload() {
autoSoulbindLevel = MMOItems.plugin.getConfig().getInt("soulbound.auto-bind.level", 1);
defaultItemLevel = MMOItems.plugin.getConfig().getInt("item-revision.default-item-level", -32767);
keepTiersWhenReroll = MMOItems.plugin.getConfig().getBoolean("item-revision.keep-tiers");
gemstonesRevIDWhenUnsocket = MMOItems.plugin.getConfig().getBoolean("item-revision.regenerate-gems-when-unsocketed", false);
}
//endregion

View File

@ -21,6 +21,8 @@ import net.Indyuce.mmoitems.api.item.mmoitem.LiveMMOItem;
import net.Indyuce.mmoitems.api.player.PlayerData;
import net.Indyuce.mmoitems.api.player.inventory.EditableEquippedItem;
import net.Indyuce.mmoitems.api.player.inventory.EquippedPlayerItem;
import net.Indyuce.mmoitems.api.player.inventory.InventoryUpdateHandler;
import net.Indyuce.mmoitems.api.util.DeathDowngrading;
import net.Indyuce.mmoitems.api.util.message.Message;
import net.Indyuce.mmoitems.skill.RegisteredSkill;
import net.Indyuce.mmoitems.stat.data.AbilityData;
@ -39,6 +41,8 @@ import org.bukkit.event.entity.PlayerDeathEvent;
import org.bukkit.event.entity.ProjectileLaunchEvent;
import org.bukkit.event.player.*;
import org.bukkit.inventory.ItemStack;
import org.bukkit.scheduler.BukkitRunnable;
import org.jetbrains.annotations.NotNull;
import java.util.*;
@ -57,8 +61,9 @@ public class PlayerListener implements Listener {
/**
* If the player dies, its time to roll the death-downgrade stat!
*/
@SuppressWarnings("InstanceofIncompatibleInterface")
@EventHandler(priority = EventPriority.MONITOR)
public void onDeathForUpgradeLoss(PlayerDeathEvent event) {
public void onDeathForUpgradeLoss(@NotNull PlayerDeathEvent event) {
// No
if (event instanceof Cancellable) { if (((Cancellable) event).isCancelled()) { return; } }
@ -66,126 +71,8 @@ public class PlayerListener implements Listener {
// Supports NPCs
if (!PlayerData.has(event.getEntity())) return;
// Get Player
PlayerData data = PlayerData.get(event.getEntity());
// Get total downgrade chance, anything less than zero is invalid
double deathChance = data.getStats().getStat(ItemStats.DOWNGRADE_ON_DEATH_CHANCE);
//DET//MMOItems.log("\u00a78DETH \u00a7cDG\u00a77 Current chance:\u00a7b " + deathChance);
if (deathChance <= 0) { return; }
List<EquippedPlayerItem> items = data.getInventory().getEquipped();
ArrayList<EditableEquippedItem> equipped = new ArrayList<>();
// Equipped Player Items yeah...
for (EquippedPlayerItem playerItem : items) {
// Null
if (playerItem == null) { continue; }
//DET//playerItem.getItem().hasData(ItemStats.NAME);
//DET//MMOItems.log("\u00a78DETH \u00a7cDG\u00a77 Item:\u00a7b " + playerItem.getItem().getData(ItemStats.NAME));
// Cannot perform operations of items that are uneditable
if (!(playerItem.getEquipped() instanceof EditableEquippedItem)) {
//DET//MMOItems.log("\u00a78DETH \u00a7cDG\u00a77 Not equippable. \u00a7cCancel");
continue; }
// Not downgradeable on death? Snooze
if (!playerItem.getItem().hasData(ItemStats.DOWNGRADE_ON_DEATH)) {
//DET//MMOItems.log("\u00a78DETH \u00a7cDG\u00a77 Not Downgradeable. \u00a7cCancel");
continue; }
// No upgrade template no snooze
if(!playerItem.getItem().hasData(ItemStats.UPGRADE)) {
//DET//MMOItems.log("\u00a78DETH \u00a7cDG\u00a77 Not Upgradeable. \u00a7cCancel");
continue; }
if (!playerItem.getItem().hasUpgradeTemplate()) {
//DET//MMOItems.log("\u00a78DETH \u00a7cDG\u00a77 Null Template. \u00a7cCancel");
continue; }
// If it can be downgraded by one level...
UpgradeData upgradeData = (UpgradeData) playerItem.getItem().getData(ItemStats.UPGRADE);
if (upgradeData.getLevel() <= upgradeData.getMin()) {
//DET//MMOItems.log("\u00a78DETH \u00a7cDG\u00a77 Too downgraded. \u00a7cCancel");
continue; }
// Okay explore stat
equipped.add((EditableEquippedItem) playerItem.getEquipped());
//DET//MMOItems.log("\u00a78DETH \u00a7cDG\u00a77 Yes. \u00a7aAccepted");
}
// Nothing to perform operations? Snooze
if (equipped.size() == 0) {
//DET//MMOItems.log("\u00a78DETH \u00a7cDG\u00a77 No items to downgrade. ");
return; }
Random random = new Random();
// Degrade those items!
while (deathChance >= 100 && equipped.size() > 0) {
// Decrease
deathChance -= 100;
// Downgrade random item
int d = random.nextInt(equipped.size());
/*
* The item was chosen, we must downgrade it by one level.
*/
EditableEquippedItem equip = equipped.get(d);
LiveMMOItem mmo = new LiveMMOItem(equip.getItem());
mmo.getUpgradeTemplate().upgradeTo(mmo, mmo.getUpgradeLevel() - 1);
// Build NBT
ItemStack bakedItem = mmo.newBuilder().build();
// Set durability to zero (full repair)
DurabilityItem dur = new DurabilityItem(event.getEntity(), mmo.newBuilder().buildNBT());
if (dur.getDurability() != dur.getMaxDurability()) {
dur.addDurability(dur.getMaxDurability());
bakedItem.setItemMeta(dur.toItem().getItemMeta());}
// AH
equip.setItem(bakedItem);
equipped.remove(d);
Message.DEATH_DOWNGRADING.format(ChatColor.RED, "#item#", SilentNumbers.getItemName(equip.getItem().getItem(), false))
.send(event.getEntity());
//DET//MMOItems.log("\u00a78DETH \u00a7cDG\u00a77 Autodegrading\u00a7a " + mmo.getData(ItemStats.NAME));
}
// If there is chance, and there is size, and there is chance success
if (deathChance > 0 && equipped.size() > 0 && random.nextInt(100) < deathChance) {
// Downgrade random item
int d = random.nextInt(equipped.size());
/*
* The item was chosen, we must downgrade it by one level.
*/
EditableEquippedItem equip = equipped.get(d);
LiveMMOItem mmo = new LiveMMOItem(equip.getItem());
mmo.getUpgradeTemplate().upgradeTo(mmo, mmo.getUpgradeLevel() - 1);
// Build NBT
ItemStack bakedItem = mmo.newBuilder().build();
// Set durability to zero (full repair)
DurabilityItem dur = new DurabilityItem(event.getEntity(), mmo.newBuilder().buildNBT());
if (dur.getDurability() != dur.getMaxDurability()) {
dur.addDurability(dur.getMaxDurability());
bakedItem.setItemMeta(dur.toItem().getItemMeta());}
// AH
equip.setItem(bakedItem);
equipped.remove(d);
Message.DEATH_DOWNGRADING.format(ChatColor.RED, "#item#", SilentNumbers.getItemName(equip.getItem().getItem(), false))
.send(event.getEntity());
}
// See description of DelayedDeathDowngrade child class for full explanation
(new DelayedDeathDowngrade(event)).runTaskLater(MMOItems.plugin, 3L);
}
/**
@ -339,4 +226,32 @@ public class PlayerListener implements Listener {
// Call event for compatibility
Bukkit.getPluginManager().callEvent(new AbilityUseEvent(playerData, abilityData, target));
}
/**
* Some plugins like to interfere with dropping items when the
* player dies, or whatever of that sort.
*
* MMOItems would hate to dupe items because of this, as such, we wait
* 3 ticks for those plugins to reasonably complete their operations and
* then downgrade the items the player still has equipped.
*
* If a plugin removes items in this time, they will be completely excluded
* and no dupes will be caused, and if a plugin adds items, they will be
* included and downgraded. I think that's reasonable behaviour.
*
* @author Gunging
*/
private static class DelayedDeathDowngrade extends BukkitRunnable {
@NotNull final PlayerDeathEvent event;
DelayedDeathDowngrade(@NotNull PlayerDeathEvent event) {this.event = event;}
@Override
public void run() {
// Downgrade player's inventory
DeathDowngrading.playerDeathDowngrade(event.getEntity());
}
}
}

View File

@ -15,7 +15,6 @@ public class RFGKeepDurability implements Listener {
@EventHandler
public void onReforge(MMOItemReforgeEvent event) {
//RFG// MMOItems.log("§8Reforge §4EFG§7 Keeping Durability");
// What was its durability? Transfer it
event.getNewMMOItem().setDamage(event.getOldMMOItem().getDamage());

View File

@ -5,6 +5,7 @@ import net.Indyuce.mmoitems.MMOItems;
import net.Indyuce.mmoitems.api.ReforgeOptions;
import net.Indyuce.mmoitems.api.event.MMOItemReforgeEvent;
import net.Indyuce.mmoitems.api.item.mmoitem.MMOItem;
import net.Indyuce.mmoitems.api.item.template.MMOItemTemplate;
import net.Indyuce.mmoitems.stat.data.GemSocketsData;
import net.Indyuce.mmoitems.stat.data.GemstoneData;
import net.Indyuce.mmoitems.stat.data.type.Mergeable;
@ -148,8 +149,10 @@ public class RFGKeepGems implements Listener {
// Get MMOItem
MMOItem restoredGem = event.getOldMMOItem().extractGemstone(lost);
if (restoredGem == null) { continue; }
// Success? Add that gem there
if (restoredGem != null) { event.getReforger().addReforgingOutput(restoredGem.newBuilder().build()); } } }
event.getReforger().addReforgingOutput(restoredGem.newBuilder().build());
} }
}
}

View File

@ -256,10 +256,13 @@ item-revision:
# ´reroll-when-updated´ is set to true.
default-item-level: -1
# Whether or not the current tier of the item should
# be carried over.
# Please note, that this value has no effect if
# ´reroll-when-updated´ is set to true.
# Unsocketing gems picks them up with the stats they had
# when first put into the item, disable this option to
# force them to be regenerated.
regenerate-gems-when-unsocketed: false
# Legacy option to carry tiers over, will take precedence
# If not specified next to the other keep- flags.
keep-tiers: true
# If an item is updated, and the new version does not
@ -303,9 +306,12 @@ item-revision:
# Modifiers of items ~ Sharp, Light, Heavy, Arcane
modifications: true
# Third party plugin compatibility
# Skins applied by MMOItems
skins: true
# Tier of the item
tier: true
# Third party plugin compatibility
advanced-enchantments: true
@ -317,6 +323,7 @@ item-revision:
upgrades: false
lore: false
exsh: false
tier: true
skins: false
reroll: true
modifications: false