diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/SlimefunItems.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/SlimefunItems.java index 129c285b2..e5f34606a 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/SlimefunItems.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/SlimefunItems.java @@ -570,7 +570,7 @@ public final class SlimefunItems { public static final SlimefunItemStack STAFF_WIND = new SlimefunItemStack("STAFF_ELEMENTAL_WIND", Material.STICK, "&6Elemental Staff &7- &b&oWind", "", "&7Element: &b&oWind", "", "&eRight Click&7 to launch yourself forward"); public static final SlimefunItemStack STAFF_FIRE = new SlimefunItemStack("STAFF_ELEMENTAL_FIRE", Material.STICK, "&6Elemental Staff &7- &c&oFire", "", "&7Element: &c&oFire"); public static final SlimefunItemStack STAFF_WATER = new SlimefunItemStack("STAFF_ELEMENTAL_WATER", Material.STICK, "&6Elemental Staff &7- &1&oWater", "", "&7Element: &1&oWater", "", "&eRight Click&7 to extinguish yourself"); - public static final SlimefunItemStack STAFF_STORM = new SlimefunItemStack("STAFF_ELEMENTAL_STORM", Material.STICK, "&6Elemental Staff &7- &8&oStorm", "", "&7Element: &8&oStorm", "", "&eRight Click&7 to summon a lightning", "&e" + StormStaff.MAX_USES + " Uses &7left"); + public static final SlimefunItemStack STAFF_STORM = new SlimefunItemStack("STAFF_ELEMENTAL_STORM", Material.STICK, "&6Elemental Staff &7- &8&oStorm", "", "&7Element: &8&oStorm", "", "&eRight Click&7 to summon a lightning", LoreBuilder.usesLeft(StormStaff.MAX_USES)); static { STAFF_WIND.addUnsafeEnchantment(Enchantment.LUCK, 1); diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/LimitedUseItem.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/LimitedUseItem.java new file mode 100644 index 000000000..6ad75fc2a --- /dev/null +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/LimitedUseItem.java @@ -0,0 +1,149 @@ +package io.github.thebusybiscuit.slimefun4.implementation.items; + +import java.util.Collections; +import java.util.List; + +import javax.annotation.Nonnull; +import javax.annotation.ParametersAreNonnullByDefault; + +import org.apache.commons.lang.Validate; +import org.bukkit.Material; +import org.bukkit.NamespacedKey; +import org.bukkit.Sound; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.persistence.PersistentDataContainer; +import org.bukkit.persistence.PersistentDataType; + +import io.github.thebusybiscuit.cscorelib2.chat.ChatColors; +import io.github.thebusybiscuit.slimefun4.api.SlimefunAddon; +import io.github.thebusybiscuit.slimefun4.core.handlers.ItemUseHandler; +import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin; +import io.github.thebusybiscuit.slimefun4.implementation.items.magical.staves.StormStaff; +import io.github.thebusybiscuit.slimefun4.utils.LoreBuilder; +import io.github.thebusybiscuit.slimefun4.utils.PatternUtils; +import me.mrCookieSlime.Slimefun.Lists.RecipeType; +import me.mrCookieSlime.Slimefun.Objects.Category; +import me.mrCookieSlime.Slimefun.api.SlimefunItemStack; + +/** + * This class represents an item with a limited number of uses. + * When the item runs out of "uses", it breaks. + * + * @author Linox + * @author Walshy + * @author TheBusyBiscuit + * @author martinbrom + * + * @see StormStaff + */ +public abstract class LimitedUseItem extends SimpleSlimefunItem { + + private final NamespacedKey defaultUsageKey = new NamespacedKey(SlimefunPlugin.instance(), "uses_left"); + private int maxUseCount = -1; + + @ParametersAreNonnullByDefault + public LimitedUseItem(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) { + super(category, item, recipeType, recipe); + + addItemHandler(getItemHandler()); + } + + /** + * Returns the number of times this item can be used. + * + * @return The number of times this item can be used. + */ + public final int getMaxUseCount() { + return maxUseCount; + } + + /** + * Sets the maximum number of times this item can be used. + * The number must be greater than zero. + * + * @param count The maximum number of times this item can be used. + * @return The {@link LimitedUseItem} for chaining of setters + */ + public final @Nonnull LimitedUseItem setMaxUseCount(int count) { + Validate.isTrue(count > 0, "The maximum use count must be greater than zero!"); + + maxUseCount = count; + return this; + } + + /** + * Returns the {@link NamespacedKey} under which will the amount of uses left stored. + * + * @return The {@link NamespacedKey} to store/load the amount of uses + */ + protected @Nonnull NamespacedKey getStorageKey() { + return defaultUsageKey; + } + + @Override + public void register(@Nonnull SlimefunAddon addon) { + if (getMaxUseCount() < 1) { + warn("The use count has not been configured correctly. It needs to be at least 1. The Item was disabled."); + } else { + super.register(addon); + } + } + + @ParametersAreNonnullByDefault + protected void damageItem(Player p, ItemStack item) { + if (item.getAmount() > 1) { + item.setAmount(item.getAmount() - 1); + + // Separate one item from the stack and damage it + ItemStack separateItem = item.clone(); + separateItem.setAmount(1); + damageItem(p, separateItem); + + // Try to give the Player the new item + if (!p.getInventory().addItem(separateItem).isEmpty()) { + // or throw it on the ground + p.getWorld().dropItemNaturally(p.getLocation(), separateItem); + } + } else { + ItemMeta meta = item.getItemMeta(); + NamespacedKey key = getStorageKey(); + PersistentDataContainer pdc = meta.getPersistentDataContainer(); + int usesLeft = pdc.getOrDefault(key, PersistentDataType.INTEGER, getMaxUseCount()); + + if (usesLeft == 1) { + p.playSound(p.getLocation(), Sound.ENTITY_ITEM_BREAK, 1, 1); + item.setAmount(0); + item.setType(Material.AIR); + } else { + usesLeft--; + pdc.set(key, PersistentDataType.INTEGER, usesLeft); + + updateItemLore(item, meta, usesLeft); + } + } + } + + @ParametersAreNonnullByDefault + private void updateItemLore(ItemStack item, ItemMeta meta, int usesLeft) { + List lore = meta.getLore(); + + String newLine = ChatColors.color(LoreBuilder.usesLeft(usesLeft)); + if (lore != null && !lore.isEmpty()) { + // find the correct line + for (int i = 0; i < lore.size(); i++) { + if (PatternUtils.USES_LEFT_LORE.matcher(lore.get(i)).matches()) { + lore.set(i, newLine); + meta.setLore(lore); + item.setItemMeta(meta); + return; + } + } + } else { + meta.setLore(Collections.singletonList(newLine)); + item.setItemMeta(meta); + } + } + +} diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/staves/StormStaff.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/staves/StormStaff.java index 17a09f4b8..b9882551c 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/staves/StormStaff.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/staves/StormStaff.java @@ -1,7 +1,5 @@ package io.github.thebusybiscuit.slimefun4.implementation.items.magical.staves; -import java.util.List; - import javax.annotation.Nonnull; import javax.annotation.ParametersAreNonnullByDefault; @@ -10,20 +8,16 @@ import org.bukkit.GameMode; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.NamespacedKey; -import org.bukkit.Sound; +import org.bukkit.World; import org.bukkit.entity.LightningStrike; import org.bukkit.entity.Player; import org.bukkit.event.entity.FoodLevelChangeEvent; import org.bukkit.inventory.ItemStack; -import org.bukkit.inventory.meta.ItemMeta; -import org.bukkit.persistence.PersistentDataType; -import io.github.thebusybiscuit.cscorelib2.chat.ChatColors; import io.github.thebusybiscuit.cscorelib2.protection.ProtectableAction; import io.github.thebusybiscuit.slimefun4.core.handlers.ItemUseHandler; -import io.github.thebusybiscuit.slimefun4.implementation.SlimefunItems; import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin; -import io.github.thebusybiscuit.slimefun4.implementation.items.SimpleSlimefunItem; +import io.github.thebusybiscuit.slimefun4.implementation.items.LimitedUseItem; import me.mrCookieSlime.Slimefun.Lists.RecipeType; import me.mrCookieSlime.Slimefun.Objects.Category; import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem; @@ -32,37 +26,31 @@ import me.mrCookieSlime.Slimefun.api.SlimefunItemStack; /** * This {@link SlimefunItem} casts a {@link LightningStrike} where you are pointing. * Unlike the other Staves, it has a limited amount of uses. - * + * * @author Linox * @author Walshy * @author TheBusyBiscuit - * */ -public class StormStaff extends SimpleSlimefunItem { +public class StormStaff extends LimitedUseItem { - private static final NamespacedKey usageKey = new NamespacedKey(SlimefunPlugin.instance(), "stormstaff_usage"); public static final int MAX_USES = 8; + private final NamespacedKey usageKey = new NamespacedKey(SlimefunPlugin.instance(), "stormstaff_usage"); + @ParametersAreNonnullByDefault public StormStaff(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) { - super(category, item, recipeType, recipe, getCraftedOutput()); - } + super(category, item, recipeType, recipe); - @Nonnull - private static ItemStack getCraftedOutput() { - ItemStack item = SlimefunItems.STAFF_STORM.clone(); - ItemMeta im = item.getItemMeta(); - List lore = im.getLore(); - - lore.set(4, ChatColors.color("&e" + MAX_USES + " Uses &7left")); - - im.setLore(lore); - item.setItemMeta(im); - return item; + setMaxUseCount(MAX_USES); } @Override - public ItemUseHandler getItemHandler() { + protected @Nonnull NamespacedKey getStorageKey() { + return usageKey; + } + + @Override + public @Nonnull ItemUseHandler getItemHandler() { return e -> { Player p = e.getPlayer(); ItemStack item = e.getItem(); @@ -87,7 +75,10 @@ public class StormStaff extends SimpleSlimefunItem { @ParametersAreNonnullByDefault private void useItem(Player p, ItemStack item, Location loc) { - loc.getWorld().strikeLightning(loc); + World world = loc.getWorld(); + if (world != null) { + world.strikeLightning(loc); + } if (item.getType() == Material.SHEARS) { return; @@ -105,39 +96,4 @@ public class StormStaff extends SimpleSlimefunItem { damageItem(p, item); } - @ParametersAreNonnullByDefault - private void damageItem(Player p, ItemStack item) { - if (item.getAmount() > 1) { - item.setAmount(item.getAmount() - 1); - - // Seperate one item from the stack and damage it - ItemStack seperateItem = item.clone(); - seperateItem.setAmount(1); - damageItem(p, seperateItem); - - // Try to give the Player the new item - if (!p.getInventory().addItem(seperateItem).isEmpty()) { - // or throw it on the ground - p.getWorld().dropItemNaturally(p.getLocation(), seperateItem); - } - } else { - ItemMeta meta = item.getItemMeta(); - int usesLeft = meta.getPersistentDataContainer().getOrDefault(usageKey, PersistentDataType.INTEGER, MAX_USES); - - if (usesLeft == 1) { - p.playSound(p.getLocation(), Sound.ENTITY_ITEM_BREAK, 1, 1); - item.setAmount(0); - } else { - usesLeft--; - meta.getPersistentDataContainer().set(usageKey, PersistentDataType.INTEGER, usesLeft); - - List lore = meta.getLore(); - lore.set(4, ChatColors.color("&e" + usesLeft + ' ' + (usesLeft > 1 ? "Uses" : "Use") + " &7left")); - meta.setLore(lore); - - item.setItemMeta(meta); - } - } - } - } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/utils/LoreBuilder.java b/src/main/java/io/github/thebusybiscuit/slimefun4/utils/LoreBuilder.java index 79d66f24e..344ce8330 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/utils/LoreBuilder.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/utils/LoreBuilder.java @@ -33,54 +33,48 @@ public final class LoreBuilder { private LoreBuilder() {} - @Nonnull - public static String radioactive(@Nonnull Radioactivity radioactivity) { + public static @Nonnull String radioactive(@Nonnull Radioactivity radioactivity) { return radioactivity.getLore(); } - @Nonnull - public static String machine(@Nonnull MachineTier tier, @Nonnull MachineType type) { + public static @Nonnull String machine(@Nonnull MachineTier tier, @Nonnull MachineType type) { return tier + " " + type; } - @Nonnull - public static String speed(float speed) { + public static @Nonnull String speed(float speed) { return "&8\u21E8 &b\u26A1 &7Speed: &b" + speed + 'x'; } - @Nonnull - public static String powerBuffer(int power) { + public static @Nonnull String powerBuffer(int power) { return power(power, " Buffer"); } - @Nonnull - public static String powerPerSecond(int power) { + public static @Nonnull String powerPerSecond(int power) { return power(power, "/s"); } - @Nonnull - public static String power(int power, @Nonnull String suffix) { + public static @Nonnull String power(int power, @Nonnull String suffix) { return "&8\u21E8 &e\u26A1 &7" + power + " J" + suffix; } - @Nonnull - public static String powerCharged(int charge, int capacity) { + public static @Nonnull String powerCharged(int charge, int capacity) { return "&8\u21E8 &e\u26A1 &7" + charge + " / " + capacity + " J"; } - @Nonnull - public static String material(@Nonnull String material) { + public static @Nonnull String material(@Nonnull String material) { return "&8\u21E8 &7Material: &b" + material; } - @Nonnull - public static String hunger(double value) { + public static @Nonnull String hunger(double value) { return "&7&oRestores &b&o" + hungerFormat.format(value) + " &7&oHunger"; } - @Nonnull - public static String range(int blocks) { + public static @Nonnull String range(int blocks) { return "&7Range: &c" + blocks + " blocks"; } + public static @Nonnull String usesLeft(int usesLeft) { + return "&e" + usesLeft + ' ' + (usesLeft > 1 ? "Uses" : "Use") + " &7left"; + } + } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/utils/PatternUtils.java b/src/main/java/io/github/thebusybiscuit/slimefun4/utils/PatternUtils.java index 59b3118c0..d70598e5b 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/utils/PatternUtils.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/utils/PatternUtils.java @@ -2,6 +2,8 @@ package io.github.thebusybiscuit.slimefun4.utils; import java.util.regex.Pattern; +import io.github.thebusybiscuit.cscorelib2.chat.ChatColors; + /** * This class is created for common-use patterns used in things such as {@link String#split(String)}.
* Every time something like {@link String#split(String)} is called it will compile a {@link Pattern}, @@ -32,4 +34,7 @@ public final class PatternUtils { public static final Pattern MINECRAFT_MATERIAL = Pattern.compile("minecraft:[a-z_]+"); public static final Pattern MINECRAFT_TAG = Pattern.compile("#minecraft:[a-z_]+"); public static final Pattern SLIMEFUN_TAG = Pattern.compile("#slimefun:[a-z_]+"); + + public static final Pattern USES_LEFT_LORE = Pattern.compile(ChatColors.color("&e[0-9]+ Uses? &7left")); + }