New Upgrade Downgrade Mechanics:

+ When the item breaks (durability), it instead dowgrades by 1 level and repairs completely.
 + When the player dies, Death Downgrade Chance stat that causes one or more of the items the player has equipped to downgrade.

 'GUI Display IDX' Stat for purely organizational purposes of the `/mmoitems browse` menu
This commit is contained in:
Gunging 2022-01-23 17:20:30 -06:00
parent afc3b8d19b
commit 4689465b6d
26 changed files with 826 additions and 143 deletions

View File

@ -170,6 +170,9 @@ public class ItemStats {
// Abilities & Upgrading
ABILITIES = new Abilities(),
UPGRADE = new UpgradeStat(),
DOWNGRADE_ON_BREAK = new BooleanStat("BREAK_DOWNGRADE", Material.DAMAGED_ANVIL, "Downgrade when Broken", new String[]{"If this item's durability reaches 0,", "it will be fully repaired but also", "downgraded by one level.", "", "&cIt will only break if it cannot be", "&cdowngraded further", "", "Requires to define an &6Upgrade Template", "Required to define &6Custom Durability"}, new String[] { "piercing", "slashing", "blunt", "offhand", "range", "tool", "armor", "consumable", "accessory" }),
DOWNGRADE_ON_DEATH = new BooleanStat("DEATH_DOWNGRADE", Material.DAMAGED_ANVIL, "Downgrade on Death", new String[]{"If the wearer of this item dies, it may", "downgrade (based on &6Death Downgrade", "&6Chance &7stat)", "", "Required to define an &6Upgrade Template", "Requires keep-inventory gamerule. "}, new String[] { "piercing", "slashing", "blunt", "offhand", "range", "tool", "armor", "consumable", "accessory" }),
DOWNGRADE_ON_DEATH_CHANCE = new EvilDoubleStat("DEATH_DOWNGRADE_CHANCE", Material.SKELETON_SKULL, "Death Downgrade Chance", new String[]{"Probability that an item with &cDowngrade ", "&con Death&7 will be downgraded when the", "player dies. ", "", "Exceeding 100% will for sure downgrade", "one item, and roll again to downgrade", "another (with the excess probability).", "&6The same item wont be downgraded twice."}, new String[]{"!miscellaneous", "!block", "all"}),
// Unique Item Stats
SKULL_TEXTURE = new SkullTextureStat(),
@ -185,13 +188,13 @@ public class ItemStats {
CUSTOM_DURABILITY = new CustomDurability(),
STORED_TAGS = new StoredTags(),
ITEM_LEVEL = new ItemLevel(),
INTERNAL_REVISION_ID = new InternalRevisionID();
INTERNAL_REVISION_ID = new InternalRevisionID(),
BROWSER_DISPLAY_IDX = new BrowserDisplayIDX();
/**
* @deprecated Item damage is now {@link ItemDamage} and
* custom durability is now {@link CustomDurability}
*/
@Deprecated
public static final ItemStat DURABILITY = ITEM_DAMAGE;
@Deprecated public static final ItemStat DURABILITY = ITEM_DAMAGE;
}

View File

@ -99,9 +99,7 @@ public class MMOItems extends LuminePlugin {
private static final int MYTHICLIB_COMPATIBILITY_INDEX = 4;
public MMOItems() {
plugin = this;
}
public MMOItems() { plugin = this; }
@Override
public void load() {

View File

@ -6,7 +6,8 @@ import net.Indyuce.mmoitems.stat.data.AbilityData;
import org.bukkit.entity.LivingEntity;
/**
* Ability that requires a direction to be cast
* Ability that requires a direction to be cast. For
* instance, a projectile like {@link Firebolt}
*
* @deprecated Abilities were moved over to MythicLib.
* Abilities are being replaced by {@link io.lumine.mythic.lib.skill.handler.SkillHandler}

View File

@ -212,6 +212,19 @@ public class Type {
return parent;
}
/**
* @return The parentmost parent of this type, or itself, if it has no parent.
*/
public Type getSupertype() {
Type parentMost = this;
while (parentMost.isSubtype()) {
parentMost = parentMost.getParent();
}
return parentMost;
}
/**
* @return Either if the two types are the same,
* or if this type is a subtype of the given type.

View File

@ -122,7 +122,7 @@ public class UpgradeTemplate {
UpgradeData dat;
if (mmoitem.hasData(ItemStats.UPGRADE)) {
dat = (UpgradeData) mmoitem.getData(ItemStats.UPGRADE);
} else { dat = new UpgradeData(null, null, false, false, 0, 100); }
} else { dat = new UpgradeData(null, null, false, false, 0, 0, 100); }
dat.setLevel(level);
mmoitem.setData(ItemStats.UPGRADE, dat);
//UPGR//MMOItems.log("\u00a76>\u00a73>\u00a7a> \u00a77Upgrading to level \u00a7e" + dat.getLevel());

View File

@ -23,6 +23,7 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.lang.reflect.Field;
import java.util.List;
public class ItemSkin extends UseItem {
public ItemSkin(Player player, NBTItem item) {
@ -41,15 +42,25 @@ public class ItemSkin extends UseItem {
}
boolean compatible = false;
//SKIN//MMOItems.log("\u00a78SKIN \u00a7eCPT\u00a77 Applying onto " + MMOUtils.getDisplayName(target.getItem()));
if (getMMOItem().hasData(ItemStats.COMPATIBLE_TYPES)) {
for (String type : ((StringListData) getMMOItem().getData(ItemStats.COMPATIBLE_TYPES)).getList()) {
//SKIN//MMOItems.log("\u00a78SKIN \u00a7eCPT\u00a77 Testing that TYPE is compatible: ");
List<String> acceptedTypes = ((StringListData) getMMOItem().getData(ItemStats.COMPATIBLE_TYPES)).getList();
for (String type : acceptedTypes) {
//SKIN//MMOItems.log("\u00a78SKIN \u00a7eCPT\u00a7e >\u00a7f " + type);
if (type.equalsIgnoreCase(targetType.getId())) {
compatible = true;
break;
}
//SKIN//MMOItems.log("\u00a78SKIN \u00a7eCPT\u00a7a Matched");
compatible = true; break; }
}
if (!compatible) {
if (!compatible && acceptedTypes.size() > 0) {
//SKIN//MMOItems.log("\u00a78SKIN \u00a7eCPT\u00a7c Incompatible");
player.playSound(player.getLocation(), Sound.ENTITY_PLAYER_LEVELUP, 1, 2);
Message.SKIN_INCOMPATIBLE.format(ChatColor.RED, "#item#", MMOUtils.getDisplayName(target.getItem()))
.send(player);
@ -58,14 +69,21 @@ public class ItemSkin extends UseItem {
}
if (getMMOItem().hasData(ItemStats.COMPATIBLE_IDS)) {
for (String id : ((StringListData) getMMOItem().getData(ItemStats.COMPATIBLE_IDS)).getList()) {
//SKIN//MMOItems.log("\u00a78SKIN \u00a7eCPT\u00a77 Testing that ID is compatible: ");
List<String> acceptedIDs = ((StringListData) getMMOItem().getData(ItemStats.COMPATIBLE_IDS)).getList();
for (String id : acceptedIDs) {
//SKIN//MMOItems.log("\u00a78SKIN \u00a7eCPT\u00a76 >\u00a7f " + id);
if (id.equalsIgnoreCase(target.getString("MMOITEMS_ITEM_ID"))) {
compatible = true;
break;
}
//SKIN//MMOItems.log("\u00a78SKIN \u00a7eCPT\u00a7a Matched");
compatible = true;break; }
}
if (!compatible) {
if (!compatible && acceptedIDs.size() > 0) {
//SKIN//MMOItems.log("\u00a78SKIN \u00a7eCPT\u00a7c Incompatible");
player.playSound(player.getLocation(), Sound.ENTITY_PLAYER_LEVELUP, 1, 2);
Message.SKIN_INCOMPATIBLE.format(ChatColor.RED, "#item#", MMOUtils.getDisplayName(target.getItem()))
.send(player);

View File

@ -1,13 +1,20 @@
package net.Indyuce.mmoitems.api.interaction.util;
import com.google.gson.JsonParser;
import com.google.gson.JsonSyntaxException;
import io.lumine.mythic.lib.MythicLib;
import io.lumine.mythic.lib.api.item.ItemTag;
import io.lumine.mythic.lib.api.item.NBTItem;
import io.lumine.mythic.lib.api.item.SupportedNBTTagValues;
import net.Indyuce.mmoitems.ItemStats;
import net.Indyuce.mmoitems.MMOItems;
import net.Indyuce.mmoitems.api.event.item.CustomDurabilityDamage;
import net.Indyuce.mmoitems.api.event.item.CustomDurabilityRepair;
import net.Indyuce.mmoitems.api.item.mmoitem.LiveMMOItem;
import net.Indyuce.mmoitems.api.item.util.LoreUpdate;
import net.Indyuce.mmoitems.api.player.PlayerData;
import net.Indyuce.mmoitems.stat.data.DoubleData;
import net.Indyuce.mmoitems.stat.data.UpgradeData;
import org.apache.commons.lang.Validate;
import org.bukkit.Bukkit;
import org.bukkit.GameMode;
@ -73,7 +80,7 @@ public class DurabilityItem {
0;
}
public Player getPlayer() {
@Nullable public Player getPlayer() {
return player;
}
@ -113,6 +120,53 @@ public class DurabilityItem {
public boolean isLostWhenBroken() {
return nbtItem.getBoolean("MMOITEMS_WILL_BREAK");
}
public boolean isDowngradedWhenBroken() {
return nbtItem.getBoolean("MMOITEMS_BREAK_DOWNGRADE");
}
/**
* <b>Assuming you already called {@link #isDowngradedWhenBroken()}</b>, when the item is
* being broken. This method will downgrade the item for one level and apply changes to
* the stored {@link #getNBTItem()}.
*
* If the item cannot be downgraded (due to not having upgrade data / reaching minimum
* upgrades), this method will return <code>null</code>, no change will be made to the
* NBTItem, and you should break the item.
*
* @return If the item could not be downgraded, and thus should break, will be <code>null</code>.
* If the item was successfully downgraded, this will uuuh, will return the NBTItem of
* the downgraded version.
*/
@Nullable public ItemStack shouldBreakWhenDowngraded() {
ItemTag uTag = ItemTag.getTagAtPath(ItemStats.UPGRADE.getNBTPath(), getNBTItem(), SupportedNBTTagValues.STRING);
if (uTag == null) { return null; }
try {
// Read data
UpgradeData data = new UpgradeData(new JsonParser().parse((String) uTag.getValue()).getAsJsonObject());
// If it cannot be downgraded (reached min), DEATH
if (data.getLevel() <= data.getMin()) { return null; }
// Downgrading operation
LiveMMOItem mmo = new LiveMMOItem(getNBTItem());
// Remove one level
mmo.getUpgradeTemplate().upgradeTo(mmo, data.getLevel() - 1);
// Build NBT
NBTItem preRet = mmo.newBuilder().buildNBT();
// Set durability to zero (full repair)
DurabilityItem dur = new DurabilityItem(getPlayer(), preRet);
dur.addDurability(dur.getMaxDurability());
// Yes
return dur.toItem();
} catch (JsonSyntaxException |IllegalStateException exception) { return null; }
}
/**
* Since
@ -120,7 +174,7 @@ public class DurabilityItem {
* @return If the item actually supports custom durability.
*/
public boolean isValid() {
return maxDurability > 0 && player.getGameMode() != GameMode.CREATIVE;
return maxDurability > 0 && player != null && player.getGameMode() != GameMode.CREATIVE;
}
public DurabilityItem addDurability(int gain) {
@ -180,8 +234,7 @@ public class DurabilityItem {
if (!barHidden) {
int damage = (durability == maxDurability) ? 0
: Math.max(1, (int) ((1. - ((double) durability / maxDurability)) * nbtItem.getItem().getType().getMaxDurability()));
nbtItem.addTag(new ItemTag("Damage", damage));
}
nbtItem.addTag(new ItemTag("Damage", damage)); }
nbtItem.addTag(new ItemTag("MMOITEMS_DURABILITY", durability));
@ -189,9 +242,9 @@ public class DurabilityItem {
ItemStack item = nbtItem.toItem();
// Item lore update
String format = MythicLib.inst().parseColors(MMOItems.plugin.getLanguage().getStatFormat("durability").replace("#m", "" + maxDurability));
String old = format.replace("#c", "" + initialDurability);
String replaced = format.replace("#c", "" + durability);
String format = MythicLib.inst().parseColors(MMOItems.plugin.getLanguage().getStatFormat("durability").replace("#m", String.valueOf(maxDurability)));
String old = format.replace("#c", String.valueOf(initialDurability));
String replaced = format.replace("#c", String.valueOf(durability));
return new LoreUpdate(item, old, replaced).updateLore();
}
}

View File

@ -1,9 +1,16 @@
package net.Indyuce.mmoitems.api.interaction.util;
import com.google.gson.JsonParser;
import com.google.gson.JsonSyntaxException;
import io.lumine.mythic.lib.api.item.ItemTag;
import io.lumine.mythic.lib.api.item.SupportedNBTTagValues;
import io.lumine.mythic.lib.api.player.EquipmentSlot;
import net.Indyuce.mmoitems.ItemStats;
import net.Indyuce.mmoitems.stat.data.UpgradeData;
import org.bukkit.entity.Player;
import io.lumine.mythic.lib.api.item.NBTItem;
import org.bukkit.inventory.ItemStack;
public class UntargetedDurabilityItem extends DurabilityItem {
private final EquipmentSlot slot;
@ -26,12 +33,38 @@ public class UntargetedDurabilityItem extends DurabilityItem {
public void update() {
if (isBroken() && isLostWhenBroken()) {
if (slot == EquipmentSlot.OFF_HAND)
getPlayer().getInventory().setItemInOffHand(null);
else
getPlayer().getInventory().setItemInMainHand(null);
return;
// Cannot update null player
if (getPlayer() == null) { return; }
// If it broke (funny)
if (isBroken()) {
// Attempt to counter by downgrading
if (isDowngradedWhenBroken()) {
ItemStack counterUpgraded = shouldBreakWhenDowngraded();
if (counterUpgraded != null) {
// Edit item
getNBTItem().getItem().setItemMeta(counterUpgraded.getItemMeta());
// No more
return;
}
}
// Still here? Remove if lost when broken
if (isLostWhenBroken()) {
// Delete item
if (slot == EquipmentSlot.OFF_HAND) {
getPlayer().getInventory().setItemInOffHand(null);
} else { getPlayer().getInventory().setItemInMainHand(null); }
// No more
return;
}
}
getNBTItem().getItem().setItemMeta(toItem().getItemMeta());

View File

@ -0,0 +1,26 @@
package net.Indyuce.mmoitems.api.player.inventory;
import io.lumine.mythic.lib.api.item.NBTItem;
import io.lumine.mythic.lib.api.player.EquipmentSlot;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.Nullable;
public abstract class EditableEquippedItem extends EquippedItem {
public EditableEquippedItem(ItemStack item, EquipmentSlot slot) {
super(item, slot);
}
public EditableEquippedItem(NBTItem item, EquipmentSlot slot) {
super(item, slot);
}
/**
* Allows editing the item, wherever it is that it is
* currently equipped, due to stats like
* {@link net.Indyuce.mmoitems.ItemStats#DOWNGRADE_ON_DEATH}
* that target equipped items.
*
* @param item Item to replace in the current slot
*/
public abstract void setItem(@Nullable ItemStack item);
}

View File

@ -18,7 +18,7 @@ public class EquippedItem {
* @param slot The corresponding MMOItems slot type
*/
public EquippedItem(ItemStack item, EquipmentSlot slot) {
this(MythicLib.plugin.getVersion().getWrapper().getNBTItem(item), slot);
this(NBTItem.get(item), slot);
}
/**

View File

@ -6,6 +6,7 @@ import net.Indyuce.mmoitems.api.item.mmoitem.VolatileMMOItem;
public class EquippedPlayerItem {
private final VolatileMMOItem item;
private final EquipmentSlot slot;
private final EquippedItem equipped;
/**
* An item equipped by a player in a specific slot
@ -13,15 +14,19 @@ public class EquippedPlayerItem {
* @param item The item equipped
*/
public EquippedPlayerItem(EquippedItem item) {
this.equipped = item;
this.item = new VolatileMMOItem(item.getItem());
this.slot = item.getSlot();
}
public VolatileMMOItem getItem() {
return item;
}
/**
* @return honestly I do not know why EquippedPlayerItem even exists?
* you can get all the values from the {@link EquippedItem}
* it came from. Its like a funny wrapper.
*/
public EquippedItem getEquipped() { return equipped; }
public EquipmentSlot getSlot() {
return slot;
}
public VolatileMMOItem getItem() { return item; }
public EquipmentSlot getSlot() { return slot; }
}

View File

@ -30,9 +30,7 @@ public class InventoryUpdateHandler {
/**
* Used to handle player inventory updates.
*/
public InventoryUpdateHandler(PlayerData player) {
this.player = player;
}
public InventoryUpdateHandler(PlayerData player) { this.player = player; }
/**
* @return All equipped MMOItems in the player's inventory. Also includes
@ -43,8 +41,7 @@ public class InventoryUpdateHandler {
}
public void updateCheck() {
if (!player.isOnline())
return;
if (!player.isOnline()) { return; }
PlayerInventory inv = player.getPlayer().getInventory();
if (isNotSame(helmet, inv.getHelmet()) || isNotSame(chestplate, inv.getChestplate()) || isNotSame(leggings, inv.getLeggings())

View File

@ -63,6 +63,7 @@ public enum Message {
UPGRADE_SUCCESS("You successfully upgraded your &6#item#&e!"),
NOT_HAVE_ITEM_UPGRADE("You don't have the item to upgrade!"),
UPGRADE_REQUIREMENT_SAFE_CHECK("You would not meet the upgraded item requirements."),
DEATH_DOWNGRADING("&cYour &6#item#&c got severely damaged that fight..."),
// Crafting stations
NOT_ENOUGH_MATERIALS("You do not have enough materials to craft this item."),

View File

@ -4,6 +4,7 @@ import io.lumine.mythic.lib.api.player.EquipmentSlot;
import net.Indyuce.mmoitems.api.player.inventory.EquippedItem;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.List;
@ -14,19 +15,25 @@ import java.util.List;
* Armor slots, mainhand and offhand.
*/
public class DefaultPlayerInventory implements PlayerInventory {
@Override
@NotNull
public List<EquippedItem> getInventory(Player player) {
List<EquippedItem> list = new ArrayList<>();
if (player.getEquipment() == null) { return list; }
// Mainhand
list.add(new EquippedItem(player.getEquipment().getItemInMainHand(), EquipmentSlot.MAIN_HAND));
list.add(new EIDefaultInventory(player, -7, player.getEquipment().getItemInMainHand(), EquipmentSlot.MAIN_HAND));
// Offhand
list.add(new EquippedItem(player.getEquipment().getItemInOffHand(), EquipmentSlot.OFF_HAND));
list.add(new EIDefaultInventory(player, -106, player.getEquipment().getItemInOffHand(), EquipmentSlot.OFF_HAND));
// Armour
for (ItemStack armor : player.getInventory().getArmorContents())
list.add(new EquippedItem(armor, EquipmentSlot.ARMOR));
// Armor
list.add(new EIDefaultInventory(player, 103, player.getEquipment().getHelmet(), EquipmentSlot.ARMOR));
list.add(new EIDefaultInventory(player, 102, player.getEquipment().getChestplate(), EquipmentSlot.ARMOR));
list.add(new EIDefaultInventory(player, 101, player.getEquipment().getLeggings(), EquipmentSlot.ARMOR));
list.add(new EIDefaultInventory(player, 100, player.getEquipment().getBoots(), EquipmentSlot.ARMOR));
return list;
}

View File

@ -0,0 +1,57 @@
package net.Indyuce.mmoitems.comp.inventory;
import io.lumine.mythic.lib.api.item.NBTItem;
import io.lumine.mythic.lib.api.player.EquipmentSlot;
import net.Indyuce.mmoitems.api.player.inventory.EditableEquippedItem;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class EIDefaultInventory extends EditableEquippedItem {
@NotNull public Player getPlayer() { return player; }
@NotNull Player player;
public int getSlotNumber() { return slotNumber; }
int slotNumber;
public EIDefaultInventory(@NotNull Player player, int slotNumber, ItemStack item, EquipmentSlot slot) {
super(item, slot);
this.player = player;
this.slotNumber = slotNumber;
}
public EIDefaultInventory(@NotNull Player player, int slotNumber, NBTItem item, EquipmentSlot slot) {
super(item, slot);
this.player = player;
this.slotNumber = slotNumber;
}
@Override
public void setItem(@Nullable ItemStack item) {
switch (getSlotNumber()) {
case -106:
getPlayer().getInventory().setItemInOffHand(item);
break;
case -7:
getPlayer().getInventory().setItemInMainHand(item);
break;
case 103:
getPlayer().getInventory().setHelmet(item);
break;
case 102:
getPlayer().getInventory().setChestplate(item);
break;
case 101:
getPlayer().getInventory().setLeggings(item);
break;
case 100:
getPlayer().getInventory().setBoots(item);
break;
default:
getPlayer().getInventory().setItem(getSlotNumber(), item);
break;
}
}
}

View File

@ -4,14 +4,15 @@ import io.lumine.mythic.lib.MythicLib;
import io.lumine.mythic.lib.api.item.ItemTag;
import io.lumine.mythic.lib.api.item.NBTItem;
import io.lumine.mythic.lib.api.util.AltChar;
import io.lumine.mythic.lib.api.util.ui.SilentNumbers;
import io.lumine.mythic.lib.version.VersionMaterial;
import io.lumine.mythic.utils.adventure.text.Component;
import net.Indyuce.mmoitems.MMOItems;
import net.Indyuce.mmoitems.MMOUtils;
import net.Indyuce.mmoitems.api.Type;
import net.Indyuce.mmoitems.api.edition.NewItemEdition;
import net.Indyuce.mmoitems.api.item.template.MMOItemTemplate;
import net.Indyuce.mmoitems.gui.edition.ItemEdition;
import net.Indyuce.mmoitems.stat.BrowserDisplayIDX;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.Material;
@ -23,6 +24,7 @@ import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemFlag;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.jetbrains.annotations.NotNull;
import java.util.*;
@ -47,106 +49,100 @@ public class ItemBrowser extends PluginInventory {
}
@Override
public Inventory getInventory() {
int[] usedSlots = type != null && type.isFourGUIMode() ? slotsAlt : slots;
int min = (page - 1) * usedSlots.length;
int max = page * usedSlots.length;
int n = 0;
@NotNull @Override public Inventory getInventory() {
/*
* Displays all possible item types if no
* type was previously selected by the player
* ------------------------------
* TYPE BROWSER
*
* Displays all possible item types if no type was previously selected by the player.
* ------------------------------
*/
if (type == null) {
int[] usedSlots = slots;
int min = (page - 1) * usedSlots.length;
int max = page * usedSlots.length;
int n = 0;
// Create inventory
Inventory inv = Bukkit.createInventory(this, 54, "Item Explorer");
// Fetch the list of types
List<Type> types = new ArrayList<>(MMOItems.plugin.getTypes().getAll());
for (int j = min; j < Math.min(max, types.size()); j++) {
Type type = types.get(j);
int items = MMOItems.plugin.getTemplates().getTemplates(type).size();
ItemStack item = type.getItem();
// Current type to display into the GUI
Type currentType = types.get(j);
// Get number of items
int items = MMOItems.plugin.getTemplates().getTemplates(currentType).size();
// Display how many items are in the type
ItemStack item = currentType.getItem();
item.setAmount(Math.max(1, Math.min(64, items)));
ItemMeta meta = item.getItemMeta();
meta.setDisplayName(ChatColor.GREEN + type.getName() + ChatColor.DARK_GRAY + " (Click to browse)");
meta.setDisplayName(ChatColor.GREEN + currentType.getName() + ChatColor.DARK_GRAY + " (Click to browse)");
meta.addItemFlags(ItemFlag.values());
List<String> lore = new ArrayList<>();
lore.add(ChatColor.GRAY + "" + ChatColor.ITALIC + "There " + (items != 1 ? "are" : "is") + " "
+ (items < 1 ? "" + ChatColor.RED + ChatColor.ITALIC + "no" : "" + ChatColor.GOLD + ChatColor.ITALIC + items) + ChatColor.GRAY
+ ChatColor.ITALIC + " item" + (items != 1 ? "s" : "") + " in that type.");
lore.add(String.valueOf(ChatColor.GRAY) + ChatColor.ITALIC + "There " + (items == 1 ? "is" : "are") + " "
+ (items < 1 ? String.valueOf(ChatColor.RED) + ChatColor.ITALIC + "no" : String.valueOf(ChatColor.GOLD) + ChatColor.ITALIC + items) + ChatColor.GRAY
+ ChatColor.ITALIC + " item" + (items == 1 ? "" : "s") + " in that currentType.");
meta.setLore(lore);
item.setItemMeta(meta);
inv.setItem(slots[n++], NBTItem.get(item).addTag(new ItemTag("typeId", type.getId())).toItem());
// Set item
inv.setItem(slots[n++], NBTItem.get(item).addTag(new ItemTag("typeId", currentType.getId())).toItem());
}
// Fill remainder slots with 'No Type' notice
ItemStack glass = VersionMaterial.GRAY_STAINED_GLASS_PANE.toItem();
ItemMeta glassMeta = glass.getItemMeta();
glassMeta.setDisplayName(ChatColor.RED + "- No type -");
glass.setItemMeta(glassMeta);
// Next Page
ItemStack next = new ItemStack(Material.ARROW);
ItemMeta nextMeta = next.getItemMeta();
nextMeta.setDisplayName(ChatColor.GREEN + "Next Page");
next.setItemMeta(nextMeta);
// Previous Page
ItemStack previous = new ItemStack(Material.ARROW);
ItemMeta previousMeta = previous.getItemMeta();
previousMeta.setDisplayName(ChatColor.GREEN + "Previous Page");
previous.setItemMeta(previousMeta);
while (n < slots.length)
inv.setItem(slots[n++], glass);
// Fill
while (n < slots.length) { inv.setItem(slots[n++], glass); }
inv.setItem(18, page > 1 ? previous : null);
inv.setItem(26, max >= MMOItems.plugin.getTypes().getAll().size() ? null : next);
// Done
return inv;
}
/*
* ------------------------------
* ITEM BROWSER
*
* Displays all the items of the chosen Type
* ------------------------------
*/
Inventory inv = Bukkit.createInventory(this, 54, (deleteMode ? ("Delete Mode: ") : ("Item Explorer: ")) + type.getName());
/*
* Build cool Item Stacks for buttons and sh
*/
ItemStack error = VersionMaterial.RED_STAINED_GLASS_PANE.toItem();
ItemMeta errorMeta = error.getItemMeta();
errorMeta.setDisplayName(ChatColor.RED + "- Error -");
List<String> errorLore = new ArrayList<>();
errorLore.add(ChatColor.GRAY + "" + ChatColor.ITALIC + "An error occurred while");
errorLore.add(ChatColor.GRAY + "" + ChatColor.ITALIC + "trying to generate that item.");
errorLore.add("\u00a7\u00a7oAn error occurred while");
errorLore.add("\u00a7\u00a7otrying to generate that item.");
errorMeta.setLore(errorLore);
error.setItemMeta(errorMeta);
List<MMOItemTemplate> templates = new ArrayList<>(MMOItems.plugin.getTemplates().getTemplates(type));
/*
* Displays every item in a specific type. Items are cached inside the
* map at the top to reduce performance impact and are directly rendered
*/
Inventory inv = Bukkit.createInventory(this, 54, (deleteMode ? ("Delete Mode: ") : ("Item Explorer: ")) + type.getName());
for (int j = min; j < Math.min(max, templates.size()); j++) {
MMOItemTemplate template = templates.get(j);
ItemStack item = template.newBuilder(playerData.getRPG()).build().newBuilder().build();
if (item == null || item.getType() == Material.AIR) {
cached.put(template.getId(), error);
inv.setItem(usedSlots[n++], error);
continue;
}
ItemMeta meta = item.getItemMeta();
List<String> lore = meta.hasLore() ? meta.getLore() : new ArrayList<>();
lore.add("");
if (deleteMode) {
lore.add(ChatColor.RED + AltChar.cross + " CLICK TO DELETE " + AltChar.cross);
meta.setDisplayName(ChatColor.RED + "DELETE: " + (meta.hasDisplayName() ? meta.getDisplayName() : MMOUtils.getDisplayName(item)));
} else {
lore.add(ChatColor.YELLOW + AltChar.smallListDash + " Left click to obtain this item.");
lore.add(ChatColor.YELLOW + AltChar.smallListDash + " Right click to edit this item.");
}
meta.setLore(lore);
item.setItemMeta(meta);
cached.put(template.getId(), item);
inv.setItem(usedSlots[n++], cached.get(template.getId()));
}
ItemStack noItem = VersionMaterial.GRAY_STAINED_GLASS_PANE.toItem();
ItemMeta noItemMeta = noItem.getItemMeta();
noItemMeta.setDisplayName(ChatColor.RED + "- No Item -");
@ -185,17 +181,121 @@ public class ItemBrowser extends PluginInventory {
ChatColor.RED + "By downloading the default resourcepack you can", ChatColor.RED + "edit the blocks however you want.",
ChatColor.RED + "You will still have to add it to your server!"));
downloadPack.setItemMeta(downloadMeta);
inv.setItem(45, downloadPack);
inv.setItem(45, downloadPack); }
// Get templates of this type
HashMap<Double, ArrayList<MMOItemTemplate>> templates = BrowserDisplayIDX.select(MMOItems.plugin.getTemplates().getTemplates(type));
/*
* -----------
* CALCULATE GUI BOUNDS AND PAGE SIZES
*
* Each display index claims the entire column of items, such that there will be
* empty spaces added to fill the inventories.
*
* In Four GUI mode, columns are four slots tall, else they are three slots tall.
* -----------
*/
int[] usedSlots = type.isFourGUIMode() ? slotsAlt : slots;
int min = (page - 1) * usedSlots.length;
int max = page * usedSlots.length;
int n = 0;
int sc = type.isFourGUIMode() ? 4 : 3;
int totalSpaceCount = 0;
for (Map.Entry<Double, ArrayList<MMOItemTemplate>> indexTemplates : templates.entrySet()) {
// Claim columns
int totalSpaceAdd = indexTemplates.getValue().size();
while (totalSpaceAdd > 0) { totalSpaceCount += sc; totalSpaceAdd -= sc; } }
/*
* Over the page-range currently in use...
*/
for (int j = min; j < Math.min(max, totalSpaceCount); j++) {
MMOItemTemplate template = BrowserDisplayIDX.getAt(j, templates);
// No template here?
if (template == null) {
// Set Item
inv.setItem(usedSlots[n], noItem);
/*
* Calculate next n from the slots.
*
* #1 Adding 7 will give you the slot immediately under
*
* #2 If it overflows, subtract 7sc (column space * 7)
* and add one
*/
n += 7;
if (n >= usedSlots.length) { n -= 7 * sc; n++; }
continue;
}
// Build item -> any errors?
ItemStack item = template.newBuilder(playerData.getRPG()).build().newBuilder().build();
if (item == null || item.getType().isAir() || !item.getType().isItem() || item.getItemMeta() == null) {
// Set Item
cached.put(template.getId(), error);
inv.setItem(usedSlots[n], error);
/*
* Calculate next n from the slots.
*
* #1 Adding 7 will give you the slot immediately under
*
* #2 If it overflows, subtract 7sc (column space * 7)
* and add one
*/
n += 7;
if (n >= usedSlots.length) { n -= 7 * sc; n++; }
continue; }
ItemMeta meta = item.getItemMeta();
List<String> lore = meta.getLore();
if (lore == null) { lore = new ArrayList<>(); }
lore.add("");
// Deleting lore?
if (deleteMode) {
lore.add(ChatColor.RED + AltChar.cross + " CLICK TO DELETE " + AltChar.cross);
meta.setDisplayName(ChatColor.RED + "DELETE: " + (meta.hasDisplayName() ? meta.getDisplayName() : MMOUtils.getDisplayName(item)));
// Editing lore?
} else {
lore.add(ChatColor.YELLOW + AltChar.smallListDash + " Left click to obtain this item.");
lore.add(ChatColor.YELLOW + AltChar.smallListDash + " Right click to edit this item."); }
meta.setLore(lore);
item.setItemMeta(meta);
// Set item
cached.put(template.getId(), item);
inv.setItem(usedSlots[n], cached.get(template.getId()));
/*
* Calculate next n from the slots.
*
* #1 Adding 7 will give you the slot immediately under
*
* #2 If it overflows, subtract 7sc (column space * 7)
* and add one
*/
n += 7;
if (n >= usedSlots.length) { n -= 7 * sc; n++; }
}
while (n < usedSlots.length)
inv.setItem(usedSlots[n++], noItem);
if (!deleteMode)
inv.setItem(51, create);
// Put the buttons
if (!deleteMode) { inv.setItem(51, create); }
inv.setItem(47, delete);
inv.setItem(49, back);
inv.setItem(18, page > 1 ? previous : null);
inv.setItem(26, max >= templates.size() ? null : next);
inv.setItem(26, max >= totalSpaceCount ? null : next);
for (int i : usedSlots) { if (SilentNumbers.isAir(inv.getItem(i))) { inv.setItem(i, noItem); } }
return inv;
}

View File

@ -84,6 +84,22 @@ public class UpgradingEdition extends EditionInventory {
maxItemMeta.setLore(maxItemLore);
maxItem.setItemMeta(maxItemMeta);
inv.setItem(40, maxItem);
int min = getEditedSection().getInt("upgrade.min", 0);
ItemStack minItem = new ItemStack(Material.BARRIER);
ItemMeta minItemMeta = minItem.getItemMeta();
minItemMeta.setDisplayName(ChatColor.GREEN + "Min Upgrades");
List<String> minItemLore = new ArrayList<>();
minItemLore.add(ChatColor.GRAY + "The minimum level your item can be");
minItemLore.add(ChatColor.GRAY + "downgraded to (by dying or breaking).");
minItemLore.add("");
minItemLore.add(ChatColor.GRAY + "Current Value: " + (min == 0 ? ChatColor.RED + "0" : ChatColor.GOLD + String.valueOf(min)));
minItemLore.add("");
minItemLore.add(ChatColor.YELLOW + AltChar.listDash + " Click to chance this value.");
minItemLore.add(ChatColor.YELLOW + AltChar.listDash + " Right click to reset.");
minItemMeta.setLore(minItemLore);
minItem.setItemMeta(minItemMeta);
inv.setItem(41, minItem);
} else {
inv.setItem(20, notAvailable);
inv.setItem(22, notAvailable);
@ -182,6 +198,17 @@ public class UpgradingEdition extends EditionInventory {
}
}
if (item.getItemMeta().getDisplayName().equals(ChatColor.GREEN + "Min Upgrades")) {
if (event.getAction() == InventoryAction.PICKUP_ALL)
new StatEdition(this, ItemStats.UPGRADE, "min").enable("Write in the chat the number you want.");
if (event.getAction() == InventoryAction.PICKUP_HALF && getEditedSection().contains("upgrade.min")) {
getEditedSection().set("upgrade.min", null);
registerTemplateEdition();
player.sendMessage(MMOItems.plugin.getPrefix() + "Successfully reset the number of min level.");
}
}
if (item.getItemMeta().getDisplayName().equals(ChatColor.GREEN + "Upgrade Template")) {
if (event.getAction() == InventoryAction.PICKUP_ALL)
new StatEdition(this, ItemStats.UPGRADE, "template").enable("Write in the chat the upgrade template ID you want.");

View File

@ -76,9 +76,32 @@ public class DurabilityListener implements Listener {
* If the item is broken and if it is meant to be lost when broken,
* do NOT cancel the event and make sure the item is destroyed
*/
if (item.isBroken() && item.isLostWhenBroken()) {
event.setDamage(999);
return;
if (item.isBroken()) {
// Attempt to counter by downgrading
if (item.isDowngradedWhenBroken()) {
ItemStack counterUpgraded = item.shouldBreakWhenDowngraded();
if (counterUpgraded != null) {
// Counter Event
event.setCancelled(true);
event.getItem().setItemMeta(counterUpgraded.getItemMeta());
// No more
return;
}
}
// Still here? Remove if lost when broken
if (item.isLostWhenBroken()) {
// Delete item
event.setDamage(999);
// Allow event to proceed
return;
}
}
event.setCancelled(true);
@ -105,10 +128,32 @@ public class DurabilityListener implements Listener {
if (item.isValid() && stack.getType().getMaxDurability() == 0) {
item.decreaseDurability(damage);
if (item.isBroken() && item.isLostWhenBroken()) {
player.getInventory().setItem(slot, null);
player.getWorld().playSound(player.getLocation(), Sound.ENTITY_ITEM_BREAK, 1.0f, 1.0f);
return;
if (item.isBroken()) {
// Attempt to counter by downgrading
if (item.isDowngradedWhenBroken()) {
ItemStack counterUpgraded = item.shouldBreakWhenDowngraded();
if (counterUpgraded != null) {
// Edit item
player.getInventory().getItem(slot).setItemMeta(counterUpgraded.getItemMeta());
// No more
return;
}
}
// Still here? Remove if lost when broken
if (item.isLostWhenBroken()) {
// Delete item
player.getInventory().setItem(slot, null);
player.getWorld().playSound(player.getLocation(), Sound.ENTITY_ITEM_BREAK, 1.0f, 1.0f);
// No more
return;
}
}
player.getInventory().getItem(slot).setItemMeta(item.toItem().getItemMeta());

View File

@ -1,27 +1,41 @@
package net.Indyuce.mmoitems.listener;
import com.google.gson.JsonParser;
import io.lumine.mythic.lib.MythicLib;
import io.lumine.mythic.lib.api.event.skill.PlayerCastSkillEvent;
import io.lumine.mythic.lib.api.item.NBTItem;
import io.lumine.mythic.lib.api.player.EquipmentSlot;
import io.lumine.mythic.lib.api.util.ui.SilentNumbers;
import io.lumine.mythic.lib.skill.trigger.TriggerType;
import io.lumine.mythic.utils.Schedulers;
import io.lumine.mythic.utils.events.extra.ArmorEquipEvent;
import net.Indyuce.mmoitems.ItemStats;
import net.Indyuce.mmoitems.MMOItems;
import net.Indyuce.mmoitems.MMOUtils;
import net.Indyuce.mmoitems.api.SoulboundInfo;
import net.Indyuce.mmoitems.api.Type;
import net.Indyuce.mmoitems.api.event.AbilityUseEvent;
import net.Indyuce.mmoitems.api.interaction.util.DurabilityItem;
import net.Indyuce.mmoitems.api.interaction.util.InteractItem;
import net.Indyuce.mmoitems.api.interaction.weapon.Weapon;
import net.Indyuce.mmoitems.api.item.mmoitem.LiveMMOItem;
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.EquippedItem;
import net.Indyuce.mmoitems.api.player.inventory.EquippedPlayerItem;
import net.Indyuce.mmoitems.api.util.message.Message;
import net.Indyuce.mmoitems.skill.RegisteredSkill;
import net.Indyuce.mmoitems.stat.data.AbilityData;
import net.Indyuce.mmoitems.stat.data.UpgradeData;
import net.Indyuce.mmoitems.stat.type.NameData;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.Material;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.bukkit.entity.Trident;
import org.bukkit.event.Cancellable;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
@ -30,10 +44,7 @@ import org.bukkit.event.entity.ProjectileLaunchEvent;
import org.bukkit.event.player.*;
import org.bukkit.inventory.ItemStack;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.*;
public class PlayerListener implements Listener {
private final Map<Player, ArrayList<ItemStack>> deathItems = new HashMap<>();
@ -41,22 +52,156 @@ public class PlayerListener implements Listener {
@EventHandler(priority = EventPriority.NORMAL)
public void loadPlayerData(PlayerJoinEvent event) {
MMOItems.plugin.getRecipes().refreshRecipeBook(event.getPlayer());
PlayerData.load(event.getPlayer());
}
PlayerData.load(event.getPlayer()); }
@EventHandler(priority = EventPriority.HIGH)
public void savePlayerData(PlayerQuitEvent event) {
PlayerData.get(event.getPlayer()).save();
public void savePlayerData(PlayerQuitEvent event) { PlayerData.get(event.getPlayer()).save(); }
public static boolean ChanceSuccess(int percentChance) {
Random rand = new Random();
return rand.nextInt(100) <= percentChance;
}
/*
/**
* If the player dies, its time to roll the death-downgrade stat!
*/
@EventHandler(priority = EventPriority.MONITOR)
public void onDeathForUpgradeLoss(PlayerDeathEvent event) {
// No
if (event instanceof Cancellable) { if (((Cancellable) event).isCancelled()) { 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());
}
}
/**
* Prevent players from dropping items which are bound to them with a
* soulbound. Items are cached inside a map waiting for the player to
* respawn. If he does not respawn the items are dropped on the ground, this
* way there don't get lost
*/
@EventHandler(priority = EventPriority.HIGH)
public void onDeath(PlayerDeathEvent event) {
public void onDeathForSoulbound(PlayerDeathEvent event) {
if (event.getKeepInventory() || !MMOItems.plugin.getLanguage().keepSoulboundOnDeath)
return;

View File

@ -27,7 +27,7 @@ public class RFGKeepUpgrades implements Listener {
//UPGRD//MMOItems.log(" \u00a7e* \u00a77Existing Upgrade Detected");
// Get current ig
UpgradeData processed = new UpgradeData(newOne.getReference(), newOne.getTemplateName(), newOne.isWorkbench(), newOne.isDestroy(), newOne.getMax(), newOne.getSuccess());
UpgradeData processed = new UpgradeData(newOne.getReference(), newOne.getTemplateName(), newOne.isWorkbench(), newOne.isDestroy(), newOne.getMax(), newOne.getMin(), newOne.getSuccess());
// Edit level
processed.setLevel(Math.min(upgrade.getLevel(), newOne.getMaxUpgrades()));

View File

@ -0,0 +1,110 @@
package net.Indyuce.mmoitems.stat;
import net.Indyuce.mmoitems.ItemStats;
import net.Indyuce.mmoitems.api.item.build.ItemStackBuilder;
import net.Indyuce.mmoitems.api.item.mmoitem.ReadMMOItem;
import net.Indyuce.mmoitems.api.item.template.MMOItemTemplate;
import net.Indyuce.mmoitems.api.util.NumericStatFormula;
import net.Indyuce.mmoitems.stat.data.type.StatData;
import net.Indyuce.mmoitems.stat.type.DoubleStat;
import org.bukkit.Material;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
public class BrowserDisplayIDX extends DoubleStat {
public BrowserDisplayIDX() { super("BROWSER_IDX", Material.GHAST_TEAR, "Browser Index", new String[] {"Used to display similar items together,", "neatly in the GUI \u00a7a/mmoitems browse", "", "Items with the same index are grouped."}, new String[]{"all"}); }
// Does not participate in actual items
@Override public void whenApplied(@NotNull ItemStackBuilder item, @NotNull StatData data) { }
@Override public void whenLoaded(@NotNull ReadMMOItem mmoitem) { }
/**
* They will be ordered.
*
* @return The MMOItem Templates separated by Index. Those with no index
* will be linked to the null index.
*/
@NotNull public static HashMap<Double, ArrayList<MMOItemTemplate>> select(@NotNull Collection<MMOItemTemplate> templates) {
HashMap<Double, ArrayList<MMOItemTemplate>> ret = new HashMap<>();
// Go through them all
for (MMOItemTemplate template : templates) {
if (template == null) { continue; }
Double armorIDX = null;
if (template.getType().getAvailableStats().contains(ItemStats.BROWSER_DISPLAY_IDX)) {
NumericStatFormula indexData = (NumericStatFormula) template.getBaseItemData().get(ItemStats.BROWSER_DISPLAY_IDX);
// Get value if it existed
if (indexData != null && indexData.getBase() != 0) { armorIDX = indexData.getBase(); }
}
// Get that map
ArrayList<MMOItemTemplate> perIndexTemplates = ret.get(armorIDX);
if (perIndexTemplates == null) { perIndexTemplates = new ArrayList<>(); }
// Include template
perIndexTemplates.add(template);
ret.put(armorIDX, perIndexTemplates);
}
return ret;
}
/**
* @param i Index you search
*
* @param templates Templates from which to gather
*
* @return The Ith Template of this Array.
*/
@Nullable public static MMOItemTemplate getAt(int i, @NotNull HashMap<Double, ArrayList<MMOItemTemplate>> templates) {
Map.Entry<Double, ArrayList<MMOItemTemplate>> nullEntry = null;
// Iterate every entry
for (Map.Entry<Double, ArrayList<MMOItemTemplate>> entry : templates.entrySet()) {
// Null entry are always displayed at the end, reference and skip.
if (entry.getKey() == null) { nullEntry = entry; continue; }
// Identify list, add null entries until it has a size multiple of four.
@NotNull ArrayList<MMOItemTemplate> list = entry.getValue();
while (list.size() % 4 != 0) { list.add(null); }
/*
* Go through each entry until i equals zero
*/
for (MMOItemTemplate observed : list) {
// Yes
if (i == 0) { return observed; }
i--;
}
}
// No more
if (nullEntry == null) { return null; }
// Still standing...
@NotNull ArrayList<MMOItemTemplate> list = nullEntry.getValue();
/*
* Go through each entry until i equals zero
*/
for (MMOItemTemplate observed : list) {
// Yes
if (i == 0) { return observed; }
i--;
}
// None found
return null;
}
}

View File

@ -13,10 +13,4 @@ public class LostWhenBroken extends BooleanStat {
public LostWhenBroken() {
super("WILL_BREAK", Material.SHEARS, "Lost when Broken?", new String[] { "If set to true, the item will be lost", "once it reaches 0 durability." }, new String[] { "!block", "all" });
}
@Override
public void whenApplied(@NotNull ItemStackBuilder item, @NotNull StatData data) {
if (((BooleanData) data).isEnabled())
item.addItemTag(new ItemTag("MMOITEMS_WILL_BREAK", true));
}
}

View File

@ -56,7 +56,7 @@ public class RepairPower extends DoubleStat implements ConsumableItemInteraction
if (durItem.getDurability() < durItem.getMaxDurability()) {
target.getItem().setItemMeta(durItem.addDurability(called.getRepaired()).toItem().getItemMeta());
Message.REPAIRED_ITEM
.format(ChatColor.YELLOW, "#item#", MMOUtils.getDisplayName(target.getItem()), "#amount#", "" + called.getRepaired())
.format(ChatColor.YELLOW, "#item#", MMOUtils.getDisplayName(target.getItem()), "#amount#", String.valueOf(called.getRepaired()))
.send(player);
CustomSoundListener.playConsumableSound(consumable.getItem(), player);
}

View File

@ -113,6 +113,15 @@ public class UpgradeStat extends ItemStat implements ConsumableItemInteraction {
return;
}
if (info[0].equals("min")) {
int i = Integer.parseInt(message);
inv.getEditedSection().set("upgrade.min", i);
inv.registerTemplateEdition();
inv.getPlayer()
.sendMessage(MMOItems.plugin.getPrefix() + "Min level successfully set to " + ChatColor.GOLD + i + ChatColor.GRAY + ".");
return;
}
if (info[0].equals("rate")) {
double d = MMOUtils.parseDouble(message);
inv.getEditedSection().set("upgrade.success", d);
@ -173,7 +182,7 @@ public class UpgradeStat extends ItemStat implements ConsumableItemInteraction {
@NotNull
@Override
public StatData getClearStatData() { return new UpgradeData(null, null, false, false, 0, 0D); }
public StatData getClearStatData() { return new UpgradeData(null, null, false, false, 0, 0, 0D); }
@Override
public boolean handleConsumableEffect(@NotNull InventoryClickEvent event, @NotNull PlayerData playerData, @NotNull Consumable consumable, @NotNull NBTItem target, Type targetType) {

View File

@ -42,22 +42,51 @@ public class UpgradeData implements StatData, RandomStatData, Cloneable {
/**
* @return Max amount of upgrades this can hold
*/
public int getMax() {
return max;
}
public int getMax() { return max; }
/**
* @return Minimum level this item can be downgraded to
*/
public int getMin() { return min; }
@Nullable private final String reference, template;
private final boolean workbench, destroy;
private final double success;
private final int max;
private final int min;
private int level;
/**
* Create a new UpgradeData
*
* @param reference Upgrade Reference to use
* @param template Upgrade Template to follow
* @param workbench If it is upgraded in workbench (I don't know for sure)?
* @param destroy If it will destroy the item if the upgrade fails
* @param max Max Level attainable
* @param success Success Chance
*/
public UpgradeData(@Nullable String reference, @Nullable String template, boolean workbench, boolean destroy, int max, double success) {
this(reference, template, workbench, destroy, max, 0, success);
}
/**
* Create a new UpgradeData
*
* @param reference Upgrade Reference to use
* @param template Upgrade Template to follow
* @param workbench If it is upgraded in workbench (I don't know for sure)?
* @param destroy If it will destroy the item if the upgrade fails
* @param max Max Level attainable
* @param min Min Level attainable through downgrading
* @param success Success Chance
*/
public UpgradeData(@Nullable String reference, @Nullable String template, boolean workbench, boolean destroy, int max, int min, double success) {
this.reference = reference;
this.template = template;
this.workbench = workbench;
this.destroy = destroy;
this.max = max;
this.min = min;
this.success = success;
}
@ -67,6 +96,7 @@ public class UpgradeData implements StatData, RandomStatData, Cloneable {
workbench = section.getBoolean("workbench");
destroy = section.getBoolean("destroy");
max = section.getInt("max");
min = section.getInt("min", 0);
success = section.getDouble("success") / 100;
}
@ -77,6 +107,7 @@ public class UpgradeData implements StatData, RandomStatData, Cloneable {
reference = object.has("Reference") ? object.get("Reference").getAsString() : null;
level = object.get("Level").getAsInt();
max = object.get("Max").getAsInt();
min = object.has("Min") ? object.get("Min").getAsInt() : 0;
success = object.get("Success").getAsDouble();
}
@ -100,9 +131,7 @@ public class UpgradeData implements StatData, RandomStatData, Cloneable {
*/
public void setLevel(int l) { level = l; }
public int getMaxUpgrades() {
return max;
}
public int getMaxUpgrades() { return max; }
public boolean canLevelUp() {
return max == 0 || level < max;
@ -150,6 +179,7 @@ public class UpgradeData implements StatData, RandomStatData, Cloneable {
json.addProperty("Destroy", destroy);
json.addProperty("Level", level);
json.addProperty("Max", max);
json.addProperty("Min", min);
json.addProperty("Success", success);
return json;
@ -169,5 +199,5 @@ public class UpgradeData implements StatData, RandomStatData, Cloneable {
public UpgradeData clone() {
try { super.clone(); } catch (CloneNotSupportedException ignored) { }
return new UpgradeData(reference, template, workbench, destroy, max, success); }
return new UpgradeData(reference, template, workbench, destroy, max, min, success); }
}

View File

@ -0,0 +1,11 @@
package net.Indyuce.mmoitems.stat.type;
import org.bukkit.Material;
public class EvilDoubleStat extends DoubleStat {
public EvilDoubleStat(String id, Material mat, String name, String[] lore) { super(id, mat, name, lore); }
public EvilDoubleStat(String id, Material mat, String name, String[] lore, String[] types, Material... materials) { super(id, mat, name, lore, types, materials); }
@Override public boolean moreIsBetter() { return false; }
}