mirror of
https://gitlab.com/phoenix-dvpmt/mmoitems.git
synced 2024-12-22 04:37:42 +01:00
Merge remote-tracking branch 'origin/master'
This commit is contained in:
commit
0b27f8ca55
4
pom.xml
4
pom.xml
@ -4,7 +4,7 @@
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>net.Indyuce</groupId>
|
||||
<artifactId>MMOItems</artifactId>
|
||||
<version>6.7-SNAPSHOT</version>
|
||||
<version>6.7.1-SNAPSHOT</version>
|
||||
<name>MMOItems</name>
|
||||
<description>A great item solution for your RPG server!!</description>
|
||||
|
||||
@ -141,7 +141,7 @@
|
||||
<dependency>
|
||||
<groupId>io.lumine</groupId>
|
||||
<artifactId>MythicLib-dist</artifactId>
|
||||
<version>1.3-R22-SNAPSHOT</version>
|
||||
<version>1.3-R25-SNAPSHOT</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
|
@ -96,7 +96,7 @@ public class MMOItems extends LuminePlugin {
|
||||
private VaultSupport vaultSupport;
|
||||
private RPGHandler rpgPlugin;
|
||||
|
||||
private static final int MYTHICLIB_COMPATIBILITY_INDEX = 5;
|
||||
private static final int MYTHICLIB_COMPATIBILITY_INDEX = 6;
|
||||
|
||||
public MMOItems() { plugin = this; }
|
||||
|
||||
@ -800,6 +800,17 @@ public class MMOItems extends LuminePlugin {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* JULES DO NOT DELETE THIS AGAIN I KNOW ITS UNUSED PRECISELY BECAUSE I ALWAYS COMMENT
|
||||
* ALL ITS USAGES BEFORE PUSHING ANY UPDATES, I USE IT FOR SPAMMY DEVELOPER MESSAGES
|
||||
*
|
||||
* Note that {@link #print(Level, String, String, String...)} is used for actual warnings
|
||||
* or such that the users may see, so dont delete that one either.
|
||||
*
|
||||
* @author Gunging
|
||||
*/
|
||||
public static void log(@Nullable String message, @NotNull String... replaces) { print(null, message, null, replaces); }
|
||||
|
||||
/**
|
||||
* @return The server's console sender.
|
||||
* @author Gunging
|
||||
|
@ -59,7 +59,10 @@ public class MMOUtils {
|
||||
switch (name) {
|
||||
case "ON_HIT": return TriggerType.ATTACK;
|
||||
case "WHEN_HIT": return TriggerType.DAMAGED;
|
||||
default: return TriggerType.valueOf(name);
|
||||
default:
|
||||
|
||||
TriggerType trigger = TriggerType.valueOf(name);
|
||||
return trigger;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -10,6 +10,9 @@ import net.Indyuce.mmoitems.api.item.template.MMOItemTemplate;
|
||||
import net.Indyuce.mmoitems.api.player.RPGPlayer;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* Consider using {@link MMOItemUIFilter}, stores the same information but works more abstractly from MythicLib.
|
||||
*/
|
||||
public class ConfigMMOItem {
|
||||
private final MMOItemTemplate template;
|
||||
private final int amount;
|
||||
@ -58,7 +61,5 @@ public class ConfigMMOItem {
|
||||
return preview == null ? (preview = template.newBuilder(0, null).build().newBuilder().build(true)).clone() : preview.clone();
|
||||
}
|
||||
|
||||
public int getAmount() {
|
||||
return amount;
|
||||
}
|
||||
public int getAmount() { return amount; }
|
||||
}
|
||||
|
@ -151,7 +151,7 @@ public class CraftingStation extends PostLoadObject {
|
||||
* parameter because old files would be out of date, instead just looks for
|
||||
* a parameter of the crafting recipe which is 'output'
|
||||
*/
|
||||
private Recipe loadRecipe(ConfigurationSection config) {
|
||||
private Recipe loadRecipe(ConfigurationSection config) throws IllegalArgumentException {
|
||||
return config.contains("output") ? new CraftingRecipe(config) : new UpgradingRecipe(config);
|
||||
}
|
||||
}
|
||||
|
@ -16,7 +16,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
*/
|
||||
public abstract class Ingredient<C extends PlayerIngredient> {
|
||||
private final String id;
|
||||
private final int amount;
|
||||
private int amount;
|
||||
|
||||
public Ingredient(String id, MMOLineConfig config) {
|
||||
this(id, config.getInt("amount", 1));
|
||||
@ -35,6 +35,7 @@ public abstract class Ingredient<C extends PlayerIngredient> {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setAmount(int amount) { this.amount = amount; }
|
||||
public int getAmount() {
|
||||
return amount;
|
||||
}
|
||||
|
@ -22,8 +22,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
public class MMOItemIngredient extends Ingredient<MMOItemPlayerIngredient> {
|
||||
private final MMOItemTemplate template;
|
||||
|
||||
@NotNull
|
||||
private final QuickNumberRange level;
|
||||
@NotNull private final QuickNumberRange level;
|
||||
private final String display;
|
||||
|
||||
public MMOItemIngredient(MMOLineConfig config) {
|
||||
|
@ -1,63 +1,164 @@
|
||||
package net.Indyuce.mmoitems.api.crafting.ingredient;
|
||||
|
||||
import io.lumine.mythic.lib.api.MMOLineConfig;
|
||||
import io.lumine.mythic.lib.api.crafting.uifilters.VanillaUIFilter;
|
||||
import io.lumine.mythic.lib.api.crafting.uimanager.ProvidedUIFilter;
|
||||
import io.lumine.mythic.lib.api.crafting.uimanager.UIFilterManager;
|
||||
import io.lumine.mythic.lib.api.item.NBTItem;
|
||||
import io.lumine.mythic.lib.api.util.LegacyComponent;
|
||||
import io.lumine.mythic.lib.api.util.ui.FriendlyFeedbackCategory;
|
||||
import io.lumine.mythic.lib.api.util.ui.FriendlyFeedbackMessage;
|
||||
import io.lumine.mythic.lib.api.util.ui.FriendlyFeedbackProvider;
|
||||
import io.lumine.mythic.lib.api.util.ui.SilentNumbers;
|
||||
import net.Indyuce.mmoitems.MMOItems;
|
||||
import net.Indyuce.mmoitems.MMOUtils;
|
||||
import net.Indyuce.mmoitems.api.crafting.ingredient.inventory.VanillaPlayerIngredient;
|
||||
import net.Indyuce.mmoitems.api.player.RPGPlayer;
|
||||
import net.Indyuce.mmoitems.api.util.message.FFPMMOItems;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class VanillaIngredient extends Ingredient<VanillaPlayerIngredient> {
|
||||
private final Material material;
|
||||
@NotNull public ProvidedUIFilter getFilter() { return filter; }
|
||||
@NotNull final ProvidedUIFilter filter;
|
||||
|
||||
@NotNull public Material getMaterial() { return material; }
|
||||
@NotNull final Material material;
|
||||
|
||||
/**
|
||||
* displayName is the itemMeta display name; display corresponds to how the
|
||||
* ingredient displays in the crafting recipe GUI item lore
|
||||
*/
|
||||
private final String displayName, display;
|
||||
@NotNull final String display;
|
||||
@Nullable final String displayName;
|
||||
|
||||
/**
|
||||
* Use vanilla stuff?
|
||||
*/
|
||||
boolean vanillaBackward = true;
|
||||
|
||||
public VanillaIngredient(MMOLineConfig config) {
|
||||
super("vanilla", config);
|
||||
|
||||
config.validate("type");
|
||||
FriendlyFeedbackProvider ffp = new FriendlyFeedbackProvider(FFPMMOItems.get());
|
||||
|
||||
material = Material.valueOf(config.getString("type").toUpperCase().replace("-", "_").replace(" ", "_"));
|
||||
// Validate type I guess
|
||||
config.validate("type");
|
||||
String itemFilter = config.getString("type", "");
|
||||
|
||||
//VING//MMOItems.log("\u00a78VING\u00a73 RD\u00a77 Reading\u00a7a " + itemFilter);
|
||||
|
||||
// UIFilter or Vanilla Backwards Compatible?
|
||||
if (itemFilter.contains(" ")) {
|
||||
vanillaBackward = false;
|
||||
//VING//MMOItems.log("\u00a78VING\u00a73 RD\u00a77 As Item Filter (yes)");
|
||||
|
||||
// Which item
|
||||
ProvidedUIFilter sweetFilter = UIFilterManager.getUIFilter(itemFilter, ffp);
|
||||
if (sweetFilter == null) {
|
||||
|
||||
// Throw message
|
||||
throw new IllegalArgumentException(SilentNumbers.collapseList(SilentNumbers.transcribeList(ffp.getFeedbackOf(FriendlyFeedbackCategory.ERROR), message -> { if (message instanceof FriendlyFeedbackMessage) { return ((FriendlyFeedbackMessage) message).forConsole(FFPMMOItems.get()); } return ""; }), ""));
|
||||
}
|
||||
|
||||
// Accepted as not-null
|
||||
filter = sweetFilter;
|
||||
|
||||
// Valid UIFilter?
|
||||
if (!filter.isValid(ffp)) {
|
||||
|
||||
// Throw message
|
||||
throw new IllegalArgumentException(SilentNumbers.collapseList(SilentNumbers.transcribeList(ffp.getFeedbackOf(FriendlyFeedbackCategory.ERROR), message -> { if (message instanceof FriendlyFeedbackMessage) { return ((FriendlyFeedbackMessage) message).forConsole(FFPMMOItems.get()); } return ""; }), ""));
|
||||
}
|
||||
|
||||
// Consistent amounts
|
||||
setAmount(filter.getAmount(getAmount()));
|
||||
filter.setAmount(getAmount());
|
||||
|
||||
// Find the display name of the item
|
||||
display = config.getString("display", findName());
|
||||
material = Material.STONE;
|
||||
//VING//MMOItems.log("\u00a78VING\u00a73 RD\u00a77 Determined\u00a7e " + filter);
|
||||
|
||||
} else {
|
||||
//VING//MMOItems.log("\u00a78VING\u00a73 RD\u00a77 As Material (eh)");
|
||||
|
||||
// Parse material
|
||||
material = Material.valueOf(itemFilter.toUpperCase().replace("-", "_").replace(" ", "_"));
|
||||
|
||||
// Filter
|
||||
filter = new ProvidedUIFilter(VanillaUIFilter.get(), material.toString(), "0");
|
||||
filter.setAmount(getAmount());
|
||||
|
||||
// Display is the name of the material, or whatever specified in the config.
|
||||
display = config.getString("display", MMOUtils.caseOnWords(material.toString().toLowerCase().replace("_", " ")));
|
||||
//VING//MMOItems.log("\u00a78VING\u00a73 RD\u00a77 Determined\u00a73 " + material.toString());
|
||||
|
||||
}
|
||||
|
||||
// Valid UIFilter?
|
||||
if (filter.getItemStack(null) == null) {
|
||||
|
||||
// Throw message
|
||||
throw new IllegalArgumentException(SilentNumbers.collapseList(SilentNumbers.transcribeList(ffp.getFeedbackOf(FriendlyFeedbackCategory.ERROR), message -> { if (message instanceof FriendlyFeedbackMessage) { return ((FriendlyFeedbackMessage) message).forConsole(FFPMMOItems.get()); } return ""; }), ""));
|
||||
}
|
||||
|
||||
// Display-Name, apparently
|
||||
displayName = config.contains("name") ? config.getString("name") : null;
|
||||
|
||||
display = config.contains("display") ? config.getString("display") : MMOUtils.caseOnWords(material.name().toLowerCase().replace("_", " "));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getKey() {
|
||||
return "vanilla:" + material.name().toLowerCase() + "_" + displayName;
|
||||
}
|
||||
@Override public String getKey() { return "vanilla:" + (vanillaBackward ? material.toString().toLowerCase() : filter.toString().toLowerCase().replace(" ", "__")) + "_" + displayName; }
|
||||
|
||||
@Override
|
||||
public String formatDisplay(String s) {
|
||||
return s.replace("#item#", display).replace("#amount#", "" + getAmount());
|
||||
}
|
||||
@Override public String formatDisplay(String s) { return s.replace("#item#", display).replace("#amount#", String.valueOf(getAmount())); }
|
||||
|
||||
@Override
|
||||
public boolean matches(VanillaPlayerIngredient ing) {
|
||||
//VING//MMOItems.log("\u00a78VING\u00a79 MCH\u00a77 Comparing given \u00a73 " + SilentNumbers.getItemName(ing.getSourceItem()) + " to expected\u00a79 " + filter);
|
||||
|
||||
if (vanillaBackward) {
|
||||
// Check for material
|
||||
if (ing.getType() != material)
|
||||
return false;
|
||||
if (ing.getType() != material) {
|
||||
//VING//MMOItems.log("\u00a78VING\u00a79 MCH\u00a7c Not right material \u00a78(expected \u00a76" + material.toString() + "\u00a78)");
|
||||
return false; }
|
||||
|
||||
//MMOItems.log("\u00a78VING\u00a79 MCH\u00a77 Display Name Ingredient:\u00a7a " + ing.getDisplayName());
|
||||
//MMOItems.log("\u00a78VING\u00a79 MCH\u00a77 Display Name Requested:\u00a7a " + displayName);
|
||||
//MMOItems.log("\u00a78VING\u00a79 MCH\u00a77 Display Name Check:\u00a7a " + (ing.getDisplayName() != null ? ing.getDisplayName().equals(displayName) : displayName == null));
|
||||
|
||||
// Check for display name
|
||||
return ing.getDisplayName() != null ? ing.getDisplayName().equals(displayName) : displayName == null;
|
||||
|
||||
} else {
|
||||
//VING//MMOItems.log("\u00a78VING\u00a79 MCH\u00a77 Poof Check \u00a73 " + filter + "\u00a77: \u00a7a " + (filter.matches(ing.getSourceItem(), true, null)));
|
||||
|
||||
// Sweet PooF matching
|
||||
return filter.matches(ing.getSourceItem(), true, null);
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public ItemStack generateItemStack(@NotNull RPGPlayer player) {
|
||||
NBTItem item = NBTItem.get(new ItemStack(material, getAmount()));
|
||||
if (displayName != null) {
|
||||
item.setDisplayNameComponent(LegacyComponent.parse(displayName));
|
||||
}
|
||||
|
||||
// Stack
|
||||
ItemStack stack = filter.getItemStack(null);
|
||||
stack.setAmount(getAmount());
|
||||
|
||||
// Apparently get as NBT Item
|
||||
NBTItem item = NBTItem.get(stack);
|
||||
|
||||
// Then rename (okay)
|
||||
if (displayName != null) { item.setDisplayNameComponent(LegacyComponent.parse(displayName)); }
|
||||
|
||||
// Return
|
||||
return item.toItem();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The name of the item the ProvidedUIFilter encodes for.
|
||||
*/
|
||||
@NotNull String findName() { return SilentNumbers.getItemName(filter.getParent().getDisplayStack(filter.getArgument(), filter.getData(), null), false); }
|
||||
}
|
||||
|
@ -2,22 +2,28 @@ package net.Indyuce.mmoitems.api.crafting.ingredient.inventory;
|
||||
|
||||
import io.lumine.mythic.lib.api.item.NBTItem;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class VanillaPlayerIngredient extends PlayerIngredient {
|
||||
@NotNull public ItemStack getSourceItem() { return sourceItem; }
|
||||
@NotNull final ItemStack sourceItem;
|
||||
|
||||
private final Material material;
|
||||
@Nullable
|
||||
private final String displayName;
|
||||
@Nullable private final String displayName;
|
||||
|
||||
public VanillaPlayerIngredient(NBTItem item) {
|
||||
super(item);
|
||||
|
||||
// Restore item
|
||||
sourceItem = item.toItem();
|
||||
this.material = item.getItem().getType();
|
||||
|
||||
ItemMeta meta = item.getItem().getItemMeta();
|
||||
this.displayName = meta.hasDisplayName() ? meta.getDisplayName() : null;
|
||||
if (meta != null) { this.displayName = meta.hasDisplayName() ? meta.getDisplayName() : null; } else { this.displayName = null; }
|
||||
}
|
||||
|
||||
public Material getType() {
|
||||
|
@ -1,49 +1,184 @@
|
||||
package net.Indyuce.mmoitems.api.crafting.recipe;
|
||||
|
||||
import io.lumine.mythic.lib.api.crafting.uimanager.ProvidedUIFilter;
|
||||
import io.lumine.mythic.lib.api.crafting.uimanager.UIFilterManager;
|
||||
import io.lumine.mythic.lib.api.util.SmartGive;
|
||||
import io.lumine.mythic.lib.api.util.ui.FriendlyFeedbackCategory;
|
||||
import io.lumine.mythic.lib.api.util.ui.FriendlyFeedbackMessage;
|
||||
import io.lumine.mythic.lib.api.util.ui.FriendlyFeedbackProvider;
|
||||
import io.lumine.mythic.lib.api.util.ui.SilentNumbers;
|
||||
import net.Indyuce.mmoitems.MMOItems;
|
||||
import net.Indyuce.mmoitems.api.crafting.ConfigMMOItem;
|
||||
import net.Indyuce.mmoitems.api.crafting.CraftingStation;
|
||||
import net.Indyuce.mmoitems.api.crafting.CraftingStatus.CraftingQueue;
|
||||
import net.Indyuce.mmoitems.api.crafting.MMOItemUIFilter;
|
||||
import net.Indyuce.mmoitems.api.crafting.ingredient.inventory.IngredientInventory;
|
||||
import net.Indyuce.mmoitems.api.event.PlayerUseCraftingStationEvent;
|
||||
import net.Indyuce.mmoitems.api.item.template.MMOItemTemplate;
|
||||
import net.Indyuce.mmoitems.api.item.util.ConfigItems;
|
||||
import net.Indyuce.mmoitems.api.player.PlayerData;
|
||||
import net.Indyuce.mmoitems.api.player.RPGPlayer;
|
||||
import net.Indyuce.mmoitems.api.util.message.FFPMMOItems;
|
||||
import net.Indyuce.mmoitems.api.util.message.Message;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.Sound;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class CraftingRecipe extends Recipe {
|
||||
private final ConfigMMOItem output;
|
||||
@NotNull public static final String UNSPECIFIED = "N/A";
|
||||
|
||||
public CraftingRecipe(@NotNull ConfigurationSection config) throws IllegalArgumentException {
|
||||
super(config);
|
||||
|
||||
craftingTime = config.getDouble("crafting-time");
|
||||
|
||||
// Legacy loading
|
||||
String uiFilter = config.getString("output.item", UNSPECIFIED);
|
||||
String miType = config.getString("output.type", UNSPECIFIED).toUpperCase().replace("-", "_").replace(" ", "_");
|
||||
String miID = config.getString("output.id", UNSPECIFIED).toUpperCase().replace("-", "_").replace(" ", "_");
|
||||
|
||||
// Yes
|
||||
FriendlyFeedbackProvider ffp = new FriendlyFeedbackProvider(FFPMMOItems.get());
|
||||
|
||||
// Both legacy specified?
|
||||
if (!UNSPECIFIED.equals(miType) && !UNSPECIFIED.equals(miID)) {
|
||||
|
||||
// Generate filter
|
||||
ProvidedUIFilter sweetOutput = UIFilterManager.getUIFilter("m", miType, miID, config.getString("output.amount", "1"), ffp);
|
||||
|
||||
// Is it null?
|
||||
if (sweetOutput == null) {
|
||||
|
||||
// Throw message
|
||||
throw new IllegalArgumentException(SilentNumbers.collapseList(SilentNumbers.transcribeList(ffp.getFeedbackOf(FriendlyFeedbackCategory.ERROR), message -> { if (message instanceof FriendlyFeedbackMessage) { return ((FriendlyFeedbackMessage) message).forConsole(FFPMMOItems.get()); } return ""; }), ""));
|
||||
}
|
||||
|
||||
// Accept
|
||||
output = sweetOutput;
|
||||
|
||||
// New method specified?
|
||||
} else if (!UNSPECIFIED.equals(uiFilter)) {
|
||||
|
||||
// Generate filter
|
||||
ProvidedUIFilter sweetOutput = UIFilterManager.getUIFilter(uiFilter, ffp);
|
||||
|
||||
// Is it null?
|
||||
if (sweetOutput == null) {
|
||||
|
||||
// Throw message
|
||||
throw new IllegalArgumentException(SilentNumbers.collapseList(SilentNumbers.transcribeList(ffp.getFeedbackOf(FriendlyFeedbackCategory.ERROR), message -> { if (message instanceof FriendlyFeedbackMessage) { return ((FriendlyFeedbackMessage) message).forConsole(FFPMMOItems.get()); } return ""; }), ""));
|
||||
}
|
||||
|
||||
// Accept
|
||||
output = sweetOutput;
|
||||
|
||||
// Invalid filter
|
||||
} else {
|
||||
|
||||
// Throw message
|
||||
throw new IllegalArgumentException(FriendlyFeedbackProvider.quickForConsole(FFPMMOItems.get(), "Config must contain a valid Type and ID, or a valid UIFilter. "));
|
||||
}
|
||||
|
||||
// Valid UIFilter?
|
||||
if (!output.isValid(ffp)) {
|
||||
|
||||
// Throw message
|
||||
throw new IllegalArgumentException(SilentNumbers.collapseList(SilentNumbers.transcribeList(ffp.getFeedbackOf(FriendlyFeedbackCategory.ERROR), message -> { if (message instanceof FriendlyFeedbackMessage) { return ((FriendlyFeedbackMessage) message).forConsole(FFPMMOItems.get()); } return ""; }), ""));
|
||||
}
|
||||
|
||||
// Valid UIFilter?
|
||||
if (output.getItemStack(ffp) == null) {
|
||||
|
||||
// Throw message
|
||||
throw new IllegalArgumentException(SilentNumbers.collapseList(SilentNumbers.transcribeList(ffp.getFeedbackOf(FriendlyFeedbackCategory.ERROR), message -> { if (message instanceof FriendlyFeedbackMessage) { return ((FriendlyFeedbackMessage) message).forConsole(FFPMMOItems.get()); } return ""; }), ""));
|
||||
}
|
||||
|
||||
// Its a MMOItem UIFilter, then?
|
||||
if (output.getParent() instanceof MMOItemUIFilter) {
|
||||
|
||||
// Find template
|
||||
MMOItemTemplate template = MMOItems.plugin.getTemplates().getTemplate(MMOItems.plugin.getTypes().get(output.getArgument()), output.getData());
|
||||
|
||||
// Not possible tho
|
||||
if (template == null) {
|
||||
|
||||
// Throw message
|
||||
throw new IllegalArgumentException(FriendlyFeedbackProvider.quickForConsole(FFPMMOItems.get(), "This should be impossible, please contact $egunging$b: $fThe ProvidedUIFilter was flagged as 'valid' but clearly is not. $enet.Indyuce.mmoitems.api.crafting.recipe$b. "));
|
||||
}
|
||||
|
||||
// Identify MMOItems operation
|
||||
identifiedMMO = new ConfigMMOItem(template, output.getAmount(1));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* There can't be any crafting time for upgrading recipes since there is no
|
||||
* way to save an MMOItem in the config file TODO save as ItemStack
|
||||
*/
|
||||
private final double craftingTime;
|
||||
public double getCraftingTime() { return craftingTime; }
|
||||
public boolean isInstant() { return craftingTime <= 0; }
|
||||
|
||||
public CraftingRecipe(ConfigurationSection config) {
|
||||
super(config);
|
||||
/**
|
||||
* @return The item specified by the player that will be produced by this recipe.
|
||||
*/
|
||||
@NotNull public ProvidedUIFilter getOutput() { return output; }
|
||||
@NotNull private final ProvidedUIFilter output;
|
||||
|
||||
craftingTime = config.getDouble("crafting-time");
|
||||
@Nullable ConfigMMOItem identifiedMMO;
|
||||
/**
|
||||
* @return The output ItemStack from this
|
||||
*/
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
@NotNull public ItemStack getOutputItemStack(@Nullable RPGPlayer rpg) {
|
||||
|
||||
// load recipe output
|
||||
output = new ConfigMMOItem(config.getConfigurationSection("output"));
|
||||
// Generate as MMOItem
|
||||
if (identifiedMMO != null && rpg != null) {
|
||||
|
||||
/*
|
||||
* Generate in the legacy way. I do this way to preserve
|
||||
* backwards compatibility, since this is how it used to
|
||||
* be done. Don't want to break that without good reason.
|
||||
*/
|
||||
return identifiedMMO.generate(rpg);
|
||||
}
|
||||
|
||||
public double getCraftingTime() {
|
||||
return craftingTime;
|
||||
// Generate from ProvidedUIFilter, guaranteed to not be null don't listen to the inspection.
|
||||
return output.getItemStack(null);
|
||||
}
|
||||
/**
|
||||
* @return The preview ItemStack from this
|
||||
*/
|
||||
@NotNull public ItemStack getPreviewItemStack() {
|
||||
|
||||
// Generate as MMOItem
|
||||
if (identifiedMMO != null) {
|
||||
|
||||
/*
|
||||
* Generate in the legacy way. I do this way to preserve
|
||||
* backwards compatibility, since this is how it used to
|
||||
* be done. Don't want to break that without good reason.
|
||||
*/
|
||||
return identifiedMMO.getPreview();
|
||||
}
|
||||
|
||||
public boolean isInstant() {
|
||||
return craftingTime <= 0;
|
||||
}
|
||||
|
||||
public ConfigMMOItem getOutput() {
|
||||
return output;
|
||||
// Generate from ProvidedUIFilter, guaranteed to not be null don't listen to the inspection.
|
||||
//return output.getParent().getDisplayStack(output.getArgument(), output.getData(), null);
|
||||
//return output.getDisplayStack(null);
|
||||
ItemStack gen = output.getParent().getDisplayStack(output.getArgument(), output.getData(), null);
|
||||
gen.setAmount(output.getAmount(1));
|
||||
ItemMeta itemMeta = gen.getItemMeta();
|
||||
if (itemMeta != null) {
|
||||
itemMeta.setDisplayName(SilentNumbers.getItemName(gen, false) + "\u00a7\u02ab");
|
||||
gen.setItemMeta(itemMeta); }
|
||||
return gen;
|
||||
}
|
||||
public int getOutputAmount() { return output.getAmount(1); }
|
||||
|
||||
@Override
|
||||
public boolean whenUsed(PlayerData data, IngredientInventory inv, CheckedRecipe recipe, CraftingStation station) {
|
||||
@ -57,7 +192,7 @@ public class CraftingRecipe extends Recipe {
|
||||
*/
|
||||
if (isInstant()) {
|
||||
|
||||
ItemStack result = hasOption(RecipeOption.OUTPUT_ITEM) ? getOutput().generate(data.getRPG()) : null;
|
||||
ItemStack result = hasOption(RecipeOption.OUTPUT_ITEM) ? getOutputItemStack(data.getRPG()) : null;
|
||||
PlayerUseCraftingStationEvent event = new PlayerUseCraftingStationEvent(data, station, recipe, result);
|
||||
Bukkit.getPluginManager().callEvent(event);
|
||||
if (event.isCancelled())
|
||||
@ -113,9 +248,7 @@ public class CraftingRecipe extends Recipe {
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack display(CheckedRecipe recipe) {
|
||||
return ConfigItems.CRAFTING_RECIPE_DISPLAY.newBuilder(recipe).build();
|
||||
}
|
||||
public ItemStack display(CheckedRecipe recipe) { return ConfigItems.CRAFTING_RECIPE_DISPLAY.newBuilder(recipe).build(); }
|
||||
|
||||
@Override
|
||||
public CheckedRecipe evaluateRecipe(PlayerData data, IngredientInventory inv) {
|
||||
|
@ -0,0 +1,94 @@
|
||||
package net.Indyuce.mmoitems.api.event;
|
||||
|
||||
import io.lumine.mythic.lib.api.item.NBTItem;
|
||||
import io.lumine.mythic.lib.damage.DamageType;
|
||||
import io.lumine.mythic.lib.player.PlayerMetadata;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.event.Event;
|
||||
import org.bukkit.event.HandlerList;
|
||||
import org.bukkit.event.entity.EntityShootBowEvent;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* Called when a MMOItems arrow or trident entity is fired.
|
||||
* <br><br>
|
||||
* Contains information even on the temporary stats the player had when
|
||||
* they executed the action, if that matters for some reason...
|
||||
* <br><br>
|
||||
* Note that this event fires before the projectile actually registers,
|
||||
* be mindful of changes made to the temporary stats because they will
|
||||
* affect the projectile.
|
||||
*/
|
||||
public class MMOItemsProjectileFireEvent extends Event {
|
||||
|
||||
/**
|
||||
* @return The item the player used to fire this arrow.
|
||||
*/
|
||||
@NotNull public NBTItem getSourceItem() { return sourceItem; }
|
||||
@NotNull NBTItem sourceItem;
|
||||
/**
|
||||
* Note that you must use {@link #setFinalDamage(double)} to modify the attack
|
||||
* damage of the projectile rather than editing the attack damage of the player
|
||||
* in here, as it will get overwritten.
|
||||
*
|
||||
* @return The stats the player had at the moment of firing the projectile.
|
||||
*/
|
||||
@NotNull public PlayerMetadata getPlayerStatsSnapshot() { return playerStatsSnapshot; }
|
||||
@NotNull PlayerMetadata playerStatsSnapshot;
|
||||
/**
|
||||
* @return The projectile entity that was fired, arrow or trident.
|
||||
*/
|
||||
@NotNull public Entity getProjectile() { return projectile; }
|
||||
@NotNull Entity projectile;
|
||||
/**
|
||||
* @return The damage this projectile will deal
|
||||
*/
|
||||
public double getFinalDamage() { return finalDamage; }
|
||||
double finalDamage;
|
||||
/**
|
||||
* @param damage The damage this projectile will deal
|
||||
*/
|
||||
public void setFinalDamage(double damage) { finalDamage = damage; }
|
||||
/**
|
||||
* @return The original damage amount
|
||||
*/
|
||||
public double getDamageMultiplicator() { return damageMultiplicator; }
|
||||
double damageMultiplicator;
|
||||
/**
|
||||
* @return The original damage amount
|
||||
*/
|
||||
public double getOriginalDamage() { return originalDamage; }
|
||||
double originalDamage;
|
||||
/**
|
||||
* @return The kinds of damage this projectile will deal, what it will scale with.
|
||||
*/
|
||||
@NotNull public DamageType[] getDamageTypes() { return damageTypes; }
|
||||
@NotNull DamageType[] damageTypes = { DamageType.PROJECTILE, DamageType.PHYSICAL, DamageType.WEAPON };
|
||||
/**
|
||||
* @param types The kinds of damage this projectile will deal, what it will scale with.
|
||||
*/
|
||||
public void setDamageTypes(@NotNull DamageType[] types) { damageTypes = types; }
|
||||
/**
|
||||
* @return The event that caused this projectile to be fired. Honestly, only for informational purposes of whatever listening API.
|
||||
*/
|
||||
@Nullable public EntityShootBowEvent getEvent() { return event; }
|
||||
@Nullable EntityShootBowEvent event;
|
||||
|
||||
public MMOItemsProjectileFireEvent(@NotNull PlayerMetadata player, @NotNull Entity projectile, @NotNull NBTItem item, @Nullable EntityShootBowEvent event, double originalDamage, double damageMultiplicator) {
|
||||
playerStatsSnapshot = player;
|
||||
this.projectile = projectile;
|
||||
sourceItem = item;
|
||||
this.originalDamage = originalDamage;
|
||||
this.damageMultiplicator= damageMultiplicator;
|
||||
finalDamage = originalDamage * damageMultiplicator;
|
||||
this.event = event;
|
||||
}
|
||||
|
||||
//region Event Standard
|
||||
private static final HandlerList handlers = new HandlerList();
|
||||
@NotNull
|
||||
@Override public HandlerList getHandlers() { return handlers; }
|
||||
public static HandlerList getHandlerList() { return handlers; }
|
||||
//endregion
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
package net.Indyuce.mmoitems.api.event;
|
||||
|
||||
import net.Indyuce.mmoitems.api.interaction.UseItem;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.Cancellable;
|
||||
import org.bukkit.event.HandlerList;
|
||||
import org.bukkit.event.player.PlayerEvent;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class MMOItemsSpecialWeaponAttack extends PlayerEvent implements Cancellable {
|
||||
|
||||
/**
|
||||
* @return The weapon used by the player that fired this event
|
||||
*/
|
||||
@NotNull public UseItem getWeapon() { return weapon; }
|
||||
@NotNull final UseItem weapon;
|
||||
|
||||
/**
|
||||
* @return The entity that is being hit by this special attack
|
||||
*/
|
||||
@Nullable public LivingEntity getTarget() { return target; }
|
||||
@Nullable final LivingEntity target;
|
||||
|
||||
public MMOItemsSpecialWeaponAttack(@NotNull Player who, @NotNull UseItem weapon, @Nullable LivingEntity target) {
|
||||
super(who);
|
||||
this.weapon = weapon;
|
||||
this.target = target;
|
||||
}
|
||||
|
||||
//region Event Standard
|
||||
private static final HandlerList handlers = new HandlerList();
|
||||
@NotNull @Override public HandlerList getHandlers() { return handlers; }
|
||||
public static HandlerList getHandlerList() { return handlers; }
|
||||
//endregion
|
||||
|
||||
//region Cancellable Standard
|
||||
boolean cancelled;
|
||||
@Override public boolean isCancelled() {
|
||||
return cancelled;
|
||||
}
|
||||
@Override public void setCancelled(boolean cancel) {
|
||||
cancelled = cancel;
|
||||
}
|
||||
//endregion
|
||||
}
|
@ -17,6 +17,7 @@ import net.Indyuce.mmoitems.api.player.PlayerData.CooldownType;
|
||||
import org.bukkit.Color;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Sound;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
@ -67,4 +68,27 @@ public class Musket extends UntargetedWeapon {
|
||||
trace.draw(loc, vec, 2, Color.BLACK);
|
||||
getPlayer().getWorld().playSound(getPlayer().getLocation(), Sound.ENTITY_ZOMBIE_ATTACK_IRON_DOOR, 2, 2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LivingEntity untargetedTargetTrace(EquipmentSlot slot) {
|
||||
|
||||
// Temporary Stats
|
||||
PlayerMetadata stats = getPlayerData().getStats().newTemporary(slot);
|
||||
|
||||
// Range
|
||||
double range = getValue(getNBTItem().getStat(ItemStats.RANGE.getId()), MMOItems.plugin.getConfig().getDouble("default.range"));
|
||||
double a = Math.toRadians(getPlayer().getEyeLocation().getYaw() + 160);
|
||||
Location loc = getPlayer().getEyeLocation().add(new Vector(Math.cos(a), 0, Math.sin(a)).multiply(.5));
|
||||
Vector vec = loc.getDirection();
|
||||
|
||||
// Raytrace
|
||||
MMORayTraceResult trace = MythicLib.plugin.getVersion().getWrapper().rayTrace(stats.getPlayer(), vec, range,
|
||||
entity -> MMOUtils.canTarget(stats.getPlayer(), entity, InteractionType.OFFENSE_ACTION));
|
||||
|
||||
// Find entity
|
||||
if (trace.hasHit()) { return trace.getHit(); }
|
||||
|
||||
// No
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -69,6 +69,26 @@ public class Staff extends UntargetedWeapon {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public LivingEntity untargetedTargetTrace(EquipmentSlot slot) {
|
||||
|
||||
// Temporary Stats
|
||||
PlayerMetadata stats = getPlayerData().getStats().newTemporary(slot);
|
||||
|
||||
// Range
|
||||
double range = getValue(getNBTItem().getStat(ItemStats.RANGE.getId()), MMOItems.plugin.getConfig().getDouble("default.range"));
|
||||
|
||||
// Raytrace
|
||||
MMORayTraceResult trace = MythicLib.plugin.getVersion().getWrapper().rayTrace(stats.getPlayer(), range,
|
||||
entity -> MMOUtils.canTarget(stats.getPlayer(), entity, InteractionType.OFFENSE_ACTION));
|
||||
|
||||
// Find Entity
|
||||
if (trace.hasHit()) { return trace.getHit(); }
|
||||
|
||||
// Nothing Found
|
||||
return null;
|
||||
}
|
||||
|
||||
public void specialAttack(LivingEntity target) {
|
||||
if (!MMOItems.plugin.getConfig().getBoolean("item-ability.staff.enabled"))
|
||||
return;
|
||||
|
@ -1,11 +1,13 @@
|
||||
package net.Indyuce.mmoitems.api.interaction.weapon.untargeted;
|
||||
|
||||
import io.lumine.mythic.lib.api.player.EquipmentSlot;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.block.Action;
|
||||
|
||||
import net.Indyuce.mmoitems.api.interaction.weapon.Weapon;
|
||||
import io.lumine.mythic.lib.api.item.NBTItem;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public abstract class UntargetedWeapon extends Weapon {
|
||||
protected final WeaponType weaponType;
|
||||
@ -24,6 +26,14 @@ public abstract class UntargetedWeapon extends Weapon {
|
||||
*/
|
||||
public abstract void untargetedAttack(EquipmentSlot slot);
|
||||
|
||||
/**
|
||||
* Predicts which target will be get hit when using {@link #untargetedAttack(EquipmentSlot)}
|
||||
* with the same exact information, this way the target is available beforehand.
|
||||
*
|
||||
* @param slot Slot being interacted with
|
||||
*/
|
||||
@Nullable public LivingEntity untargetedTargetTrace(EquipmentSlot slot) { return null; }
|
||||
|
||||
public WeaponType getWeaponType() {
|
||||
return weaponType;
|
||||
}
|
||||
|
@ -17,6 +17,7 @@ import net.Indyuce.mmoitems.api.interaction.util.UntargetedDurabilityItem;
|
||||
import net.Indyuce.mmoitems.api.player.PlayerData.CooldownType;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Particle;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
@ -54,4 +55,26 @@ public class Whip extends UntargetedWeapon {
|
||||
(tick) -> tick.getWorld().spawnParticle(Particle.CRIT, tick, 0, .1, .1, .1, 0));
|
||||
getPlayer().getWorld().playSound(getPlayer().getLocation(), VersionSound.ENTITY_FIREWORK_ROCKET_BLAST.toSound(), 1, 2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LivingEntity untargetedTargetTrace(EquipmentSlot slot) {
|
||||
|
||||
// Temporary Stats
|
||||
PlayerMetadata stats = getPlayerData().getStats().newTemporary(slot);
|
||||
|
||||
// Range
|
||||
double range = getValue(getNBTItem().getStat(ItemStats.RANGE.getId()), MMOItems.plugin.getConfig().getDouble("default.range"));
|
||||
double a = Math.toRadians(getPlayer().getEyeLocation().getYaw() + 160);
|
||||
Location loc = getPlayer().getEyeLocation().add(new Vector(Math.cos(a), 0, Math.sin(a)).multiply(.5));
|
||||
|
||||
// Ray Trace
|
||||
MMORayTraceResult trace = MythicLib.plugin.getVersion().getWrapper().rayTrace(stats.getPlayer(), range,
|
||||
entity -> MMOUtils.canTarget(stats.getPlayer(), entity, InteractionType.OFFENSE_ACTION));
|
||||
|
||||
// Find entity
|
||||
if (trace.hasHit()) { return trace.getHit(); }
|
||||
|
||||
// No
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -178,9 +178,7 @@ public class ItemStackBuilder {
|
||||
|
||||
// Get Template
|
||||
MMOItemTemplate template = MMOItems.plugin.getTemplates().getTemplate(builtMMOItem.getType(), builtMMOItem.getId());
|
||||
if (template == null) {
|
||||
throw new IllegalArgumentException("MMOItem $r" + builtMMOItem.getType().getId() + " " + builtMMOItem.getId() + "$b doesn't exist.");
|
||||
}
|
||||
if (template == null) { throw new IllegalArgumentException("MMOItem $r" + builtMMOItem.getType().getId() + " " + builtMMOItem.getId() + "$b doesn't exist."); }
|
||||
|
||||
// Make necessary lore changes
|
||||
((Previewable) stat).whenPreviewed(this, builtMMOItem.getData(stat), template.getBaseItemData().get(stat));
|
||||
@ -195,11 +193,8 @@ public class ItemStackBuilder {
|
||||
} catch (IllegalArgumentException | NullPointerException exception) {
|
||||
|
||||
// That
|
||||
MMOItems.plugin.getLogger().log(Level.WARNING, FriendlyFeedbackProvider.quickForConsole(FFPMMOItems.get(),
|
||||
"An error occurred while trying to generate item '$f{0}$b' with stat '$f{1}$b': {2}",
|
||||
builtMMOItem.getId(),
|
||||
stat.getId(),
|
||||
exception.getMessage()));
|
||||
MMOItems.print(Level.WARNING, "An error occurred while trying to generate item '$f{0}$b' with stat '$f{1}$b': {2}",
|
||||
"ItemStackBuilder", builtMMOItem.getId(), stat.getId(), exception.getMessage());
|
||||
}
|
||||
|
||||
// Display gem stone lore hint thing
|
||||
|
@ -109,11 +109,11 @@ public class CraftingRecipeDisplay extends ConfigItem {
|
||||
lore.add(conditionsIndex++, condition.format());
|
||||
}
|
||||
|
||||
ItemStack item = craftingRecipe.getOutput().getPreview();
|
||||
int amount = craftingRecipe.getOutput().getAmount();
|
||||
ItemStack item = craftingRecipe.getPreviewItemStack();
|
||||
int amount = craftingRecipe.getOutputAmount();
|
||||
|
||||
if (amount > 64)
|
||||
lore.add(0, Message.STATION_BIG_STACK.format(ChatColor.GOLD, "#size#", "" + amount).toString());
|
||||
lore.add(0, Message.STATION_BIG_STACK.format(ChatColor.GOLD, "#size#", String.valueOf(amount)).toString());
|
||||
else
|
||||
item.setAmount(amount);
|
||||
|
||||
|
@ -75,7 +75,7 @@ public class QueueItemDisplay extends ConfigItem {
|
||||
for (String key : replace.keySet())
|
||||
lore.set(lore.indexOf(key), replace.get(key).replace("#left#", formatDelay(crafting.getLeft())));
|
||||
|
||||
ItemStack item = crafting.getRecipe().getOutput().getPreview();
|
||||
ItemStack item = crafting.getRecipe().getPreviewItemStack();
|
||||
item.setAmount(position);
|
||||
ItemMeta meta = item.getItemMeta();
|
||||
meta.addItemFlags(ItemFlag.values());
|
||||
|
@ -1,34 +1,47 @@
|
||||
package net.Indyuce.mmoitems.comp.mmocore;
|
||||
|
||||
import io.lumine.mythic.lib.version.VersionMaterial;
|
||||
import net.Indyuce.mmocore.MMOCore;
|
||||
import net.Indyuce.mmocore.api.event.PlayerChangeClassEvent;
|
||||
import net.Indyuce.mmocore.api.event.PlayerLevelUpEvent;
|
||||
import net.Indyuce.mmocore.api.event.PlayerResourceUpdateEvent;
|
||||
import net.Indyuce.mmocore.api.player.PlayerData;
|
||||
import net.Indyuce.mmocore.api.player.attribute.PlayerAttribute;
|
||||
import net.Indyuce.mmocore.api.player.stats.StatType;
|
||||
import net.Indyuce.mmocore.experience.Profession;
|
||||
import net.Indyuce.mmoitems.MMOItems;
|
||||
import net.Indyuce.mmoitems.api.player.RPGPlayer;
|
||||
import net.Indyuce.mmoitems.comp.mmocore.stat.Required_Attribute;
|
||||
import net.Indyuce.mmoitems.comp.mmocore.stat.Required_Profession;
|
||||
import net.Indyuce.mmoitems.comp.rpg.RPGHandler;
|
||||
import net.Indyuce.mmoitems.stat.type.DoubleStat;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
public class MMOCoreHook implements RPGHandler, Listener {
|
||||
|
||||
/**
|
||||
* Called when MMOItems enables
|
||||
* <p>
|
||||
* These stats are only updated on a server reload because that
|
||||
* class has to be instanciated again for the registered stats to update
|
||||
* class has to be instantiated again for the registered stats to update
|
||||
*/
|
||||
public MMOCoreHook() {
|
||||
for (PlayerAttribute attribute : MMOCore.plugin.attributeManager.getAll())
|
||||
MMOItems.plugin.getStats().register(new Required_Attribute(attribute));
|
||||
for (Profession profession : MMOCore.plugin.professionManager.getAll())
|
||||
for (Profession profession : MMOCore.plugin.professionManager.getAll()) {
|
||||
|
||||
// Adds profession specific Additional Experience stats.
|
||||
MMOItems.plugin.getStats().register(new DoubleStat((StatType.ADDITIONAL_EXPERIENCE.name() + '_' + profession.getId())
|
||||
.replace('-', '_').replace(' ', '_').toUpperCase(Locale.ROOT),
|
||||
VersionMaterial.EXPERIENCE_BOTTLE.toMaterial(), profession.getName() + ' ' + "Additional Experience (MMOCore)"
|
||||
, new String[]{"Additional MMOCore profession " + profession.getName() + " experience in %."}, new String[]{"!block", "all"}));
|
||||
|
||||
MMOItems.plugin.getStats().register(new Required_Profession(profession));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refreshStats(net.Indyuce.mmoitems.api.player.PlayerData data) {
|
||||
|
@ -1,11 +1,14 @@
|
||||
package net.Indyuce.mmoitems.comp.mythicmobs;
|
||||
|
||||
import io.lumine.xikage.mythicmobs.MythicMobs;
|
||||
import io.lumine.xikage.mythicmobs.api.bukkit.events.MythicMechanicLoadEvent;
|
||||
import io.lumine.xikage.mythicmobs.api.bukkit.events.MythicReloadedEvent;
|
||||
import io.lumine.xikage.mythicmobs.mobs.MythicMob;
|
||||
import net.Indyuce.mmoitems.MMOItems;
|
||||
import net.Indyuce.mmoitems.api.item.mmoitem.MMOItem;
|
||||
import net.Indyuce.mmoitems.api.player.PlayerData;
|
||||
import net.Indyuce.mmoitems.comp.mythicmobs.mechanics.MMOItemsArrowVolleyMechanic;
|
||||
import net.Indyuce.mmoitems.comp.mythicmobs.mechanics.MMOItemsOnShootAura;
|
||||
import net.Indyuce.mmoitems.comp.mythicmobs.stat.FactionDamage;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
@ -29,6 +32,22 @@ public class MythicMobsCompatibility implements Listener {
|
||||
Bukkit.getPluginManager().registerEvents(this, MMOItems.plugin);
|
||||
}
|
||||
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGH)
|
||||
public void b(MythicMechanicLoadEvent event) {
|
||||
|
||||
// Switch Mechanic ig
|
||||
switch (event.getMechanicName().toLowerCase()) {
|
||||
case "mmoitemsvolley":
|
||||
event.register(new MMOItemsArrowVolleyMechanic(event.getContainer().getConfigLine(), event.getConfig()));
|
||||
break;
|
||||
case "onmmoitemuse":
|
||||
event.register(new MMOItemsOnShootAura(event.getContainer().getConfigLine(), event.getConfig()));
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* MythicLib skill handlers are reloaded on priority {@link EventPriority#NORMAL}
|
||||
* MMOCore and MMOItems use HIGH or HIGHEST
|
||||
|
@ -0,0 +1,187 @@
|
||||
package net.Indyuce.mmoitems.comp.mythicmobs.mechanics;
|
||||
|
||||
import io.lumine.mythic.lib.api.crafting.uimanager.ProvidedUIFilter;
|
||||
import io.lumine.mythic.lib.api.crafting.uimanager.UIFilterManager;
|
||||
import io.lumine.xikage.mythicmobs.adapters.AbstractEntity;
|
||||
import io.lumine.xikage.mythicmobs.adapters.AbstractLocation;
|
||||
import io.lumine.xikage.mythicmobs.adapters.SkillAdapter;
|
||||
import io.lumine.xikage.mythicmobs.adapters.bukkit.BukkitAdapter;
|
||||
import io.lumine.xikage.mythicmobs.io.MythicLineConfig;
|
||||
import io.lumine.xikage.mythicmobs.skills.*;
|
||||
import io.lumine.xikage.mythicmobs.skills.placeholders.parsers.PlaceholderDouble;
|
||||
import io.lumine.xikage.mythicmobs.skills.placeholders.parsers.PlaceholderFloat;
|
||||
import io.lumine.xikage.mythicmobs.skills.placeholders.parsers.PlaceholderInt;
|
||||
import net.Indyuce.mmoitems.MMOItems;
|
||||
import net.Indyuce.mmoitems.listener.ItemUse;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.entity.Arrow;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.entity.EntityShootBowEvent;
|
||||
import org.bukkit.inventory.EquipmentSlot;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.util.Vector;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* An arrow volley method but uses the stats of the bow
|
||||
* held by the player that is casting this skill, or at
|
||||
* least a scaled version of them!
|
||||
*
|
||||
* @author Gunging
|
||||
*/
|
||||
public class MMOItemsArrowVolleyMechanic extends SkillMechanic implements ITargetedEntitySkill, ITargetedLocationSkill {
|
||||
|
||||
@NotNull PlaceholderInt amount, spread, fireTicks, removeDelay;
|
||||
@NotNull PlaceholderFloat velocity, scale;
|
||||
@NotNull PlaceholderDouble xOffset, yOffset, zOffset, fOffset, sOffset;
|
||||
|
||||
@Nullable ItemStack arrowItem;
|
||||
boolean fullEvent;
|
||||
boolean scalePerArrow;
|
||||
boolean fromOrigin;
|
||||
|
||||
public MMOItemsArrowVolleyMechanic(String line, MythicLineConfig mlc) {
|
||||
super(line, mlc);
|
||||
threadSafetyLevel = ThreadSafetyLevel.SYNC_ONLY;
|
||||
|
||||
amount = mlc.getPlaceholderInteger(new String[] {"amount", "arrows", "a"}, 20);
|
||||
spread = mlc.getPlaceholderInteger(new String[] {"spread", "s"}, 45);
|
||||
fireTicks = mlc.getPlaceholderInteger(new String[] {"fireticks", "ft", "f"}, 0);
|
||||
removeDelay = mlc.getPlaceholderInteger(new String[] {"removedelay", "rd", "r"}, 200);
|
||||
velocity = mlc.getPlaceholderFloat(new String[] {"velocity", "v"}, 20);
|
||||
scale = mlc.getPlaceholderFloat(new String[] {"statsscale", "ss"}, 1);
|
||||
|
||||
fullEvent = mlc.getBoolean(new String[] {"fullevent", "fe"}, false);
|
||||
scalePerArrow = mlc.getBoolean(new String[] {"scaleperarrow", "spa"}, false);
|
||||
fromOrigin = mlc.getBoolean(new String[] {"fromorigin", "fo"}, false);
|
||||
|
||||
//region Get Arrow Item
|
||||
String itemFilter = mlc.getString(new String[] {"arrowitem", "item", "ai"}, null);
|
||||
if (itemFilter != null) {
|
||||
ProvidedUIFilter uiFilter = UIFilterManager.getUIFilter(itemFilter, null);
|
||||
if (uiFilter != null) {
|
||||
if (uiFilter.isValid(null) && uiFilter.getParent().fullyDefinesItem()) {
|
||||
uiFilter.setAmount(1);
|
||||
|
||||
// Generate Item
|
||||
arrowItem = uiFilter.getItemStack(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
//endregion
|
||||
|
||||
// Offsets
|
||||
xOffset = mlc.getPlaceholderDouble(new String[] {"startxoffset", "sxo"}, 0);
|
||||
yOffset = mlc.getPlaceholderDouble(new String[] {"startyoffset", "syo"}, 3);
|
||||
zOffset = mlc.getPlaceholderDouble(new String[] {"startzoffset", "szo"}, 0);
|
||||
fOffset = mlc.getPlaceholderDouble(new String[] {"startfoffset", "sfo"}, 0);
|
||||
sOffset = mlc.getPlaceholderDouble(new String[] {"startsoffset", "sso"}, 0);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean castAtLocation(SkillMetadata data, AbstractLocation target) {
|
||||
|
||||
// Caster must be a player
|
||||
if (data.getCaster().getEntity().getBukkitEntity() instanceof Player) {
|
||||
|
||||
// MMOItems Volley!
|
||||
executeMIVolley(data.getCaster(), data, target, amount.get(data), velocity.get(data) * 0.1F, spread.get(data), fireTicks.get(data), removeDelay.get(data), scale);
|
||||
|
||||
} else {
|
||||
|
||||
// Run as normal mythicmobs arrow volley
|
||||
SkillAdapter.get().executeVolley(data.getCaster(), target, amount.get(data), velocity.get(data) * 0.1F, spread.get(data), fireTicks.get(data), removeDelay.get(data));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean castAtEntity(SkillMetadata data, AbstractEntity target) {
|
||||
|
||||
// Caster must be a player
|
||||
if (data.getCaster().getEntity().getBukkitEntity() instanceof Player) {
|
||||
|
||||
// MMOItems Volley!
|
||||
executeMIVolley(data.getCaster(), data, target.getLocation(), amount.get(data,target), velocity.get(data) * 0.1F, spread.get(data), fireTicks.get(data), removeDelay.get(data), scale);
|
||||
|
||||
} else {
|
||||
|
||||
// Run as normal mythicmobs arrow volley
|
||||
SkillAdapter.get().executeVolley(data.getCaster(), target.getLocation(), amount.get(data,target), velocity.get(data) * 0.1F, spread.get(data), fireTicks.get(data), removeDelay.get(data));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
public void executeMIVolley(@NotNull SkillCaster caster, @NotNull SkillMetadata data, @NotNull AbstractLocation t, int amount, float velocity, float spread, int fireTicks, int removeDelay, @NotNull PlaceholderFloat statsMultiplier) {
|
||||
|
||||
// Skill caster MUST be a player
|
||||
if (!(caster.getEntity().getBukkitEntity() instanceof Player)) { return; }
|
||||
Player player = (Player) caster.getEntity().getBukkitEntity();
|
||||
|
||||
// Target yeah
|
||||
Location target = BukkitAdapter.adapt(t);
|
||||
Location spawn = BukkitAdapter.adapt(fromOrigin ? data.getOrigin() : caster.getLocation()).clone();
|
||||
|
||||
//region Calculate Offsets
|
||||
Vector forward = spawn.getDirection().normalize();
|
||||
Vector side = (new Vector(-forward.getZ(), 0.00001, forward.getX())).normalize();
|
||||
|
||||
double fS = fOffset.get(data);
|
||||
double sS = sOffset.get(data);
|
||||
|
||||
spawn.setX(spawn.getX() + xOffset.get(data) + (forward.getX() * fS) + (side.getX() * sS));
|
||||
spawn.setY(spawn.getY() + yOffset.get(data) + (forward.getY() * fS) + (side.getY() * sS));
|
||||
spawn.setZ(spawn.getZ() + zOffset.get(data) + (forward.getZ() * fS) + (side.getZ() * sS));
|
||||
//endregion
|
||||
|
||||
// Direction vector
|
||||
Vector v = target.toVector().subtract(spawn.toVector()).normalize();
|
||||
|
||||
// Player bow item is held??
|
||||
ItemStack bowItem = player.getInventory().getItemInMainHand().clone();
|
||||
ItemStack localArrowItem = (arrowItem != null ? arrowItem.clone() : new ItemStack(Material.ARROW));
|
||||
ItemUse use = new ItemUse();
|
||||
|
||||
// Parse
|
||||
float arrowForce = statsMultiplier.get(data);
|
||||
|
||||
// Spawn arrows
|
||||
ArrayList<Arrow> arrowList = new ArrayList<>();
|
||||
for (int i = 0; i < amount; i++) {
|
||||
|
||||
// Spawn Arrow
|
||||
Arrow a = player.getWorld().spawnArrow(spawn, v, velocity, (spread/10.0F));
|
||||
a.setVelocity(a.getVelocity());
|
||||
|
||||
// Identify arrow as the player's
|
||||
a.setShooter(player);
|
||||
|
||||
// Run Event
|
||||
EntityShootBowEvent shootBowEvent = new EntityShootBowEvent(player, bowItem, localArrowItem, a, EquipmentSlot.HAND, arrowForce, false);
|
||||
if (fullEvent) { Bukkit.getPluginManager().callEvent(shootBowEvent); } else { use.handleCustomBows(shootBowEvent); }
|
||||
|
||||
// Cancelled???
|
||||
if (shootBowEvent.isCancelled()) { a.remove(); continue; }
|
||||
|
||||
// Set on fire I guess
|
||||
if(fireTicks > 0) { a.setFireTicks(fireTicks); }
|
||||
|
||||
// Add to list
|
||||
arrowList.add(a);
|
||||
|
||||
// Recalculate
|
||||
if (scalePerArrow) { arrowForce = statsMultiplier.get(data); }
|
||||
}
|
||||
|
||||
// Remove after delay
|
||||
Bukkit.getScheduler().scheduleSyncDelayedTask(MMOItems.plugin, () -> {
|
||||
for (Arrow a : arrowList) { a.remove(); }arrowList.clear(); }, removeDelay);
|
||||
}
|
||||
}
|
@ -0,0 +1,211 @@
|
||||
package net.Indyuce.mmoitems.comp.mythicmobs.mechanics;
|
||||
|
||||
import io.lumine.xikage.mythicmobs.MythicMobs;
|
||||
import io.lumine.xikage.mythicmobs.adapters.AbstractEntity;
|
||||
import io.lumine.xikage.mythicmobs.adapters.bukkit.BukkitAdapter;
|
||||
import io.lumine.xikage.mythicmobs.io.MythicLineConfig;
|
||||
import io.lumine.xikage.mythicmobs.mobs.GenericCaster;
|
||||
import io.lumine.xikage.mythicmobs.skills.*;
|
||||
import io.lumine.xikage.mythicmobs.skills.auras.Aura;
|
||||
import io.lumine.xikage.mythicmobs.skills.placeholders.parsers.PlaceholderString;
|
||||
import io.lumine.xikage.mythicmobs.utils.Events;
|
||||
import net.Indyuce.mmoitems.MMOItems;
|
||||
import net.Indyuce.mmoitems.api.event.MMOItemsSpecialWeaponAttack;
|
||||
import net.Indyuce.mmoitems.api.interaction.weapon.Gauntlet;
|
||||
import net.Indyuce.mmoitems.api.interaction.weapon.untargeted.*;
|
||||
import org.bukkit.scheduler.BukkitRunnable;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* Sure there is the 'onShoot' aura for bows, but what about
|
||||
* musket and crossbow and lute and...?
|
||||
*
|
||||
* This Aura will cover all of those.
|
||||
*
|
||||
* @author Gunging
|
||||
*/
|
||||
public class MMOItemsOnShootAura extends Aura implements ITargetedEntitySkill {
|
||||
@NotNull PlaceholderString skillName;
|
||||
@NotNull String weaponTypes;
|
||||
@Nullable Skill metaskill;
|
||||
boolean cancelEvent;
|
||||
boolean forceAsPower;
|
||||
|
||||
@NotNull final ArrayList<UseItemTypes> auraWeapons = new ArrayList<>();
|
||||
|
||||
public MMOItemsOnShootAura(String skill, MythicLineConfig mlc) {
|
||||
super(skill, mlc);
|
||||
skillName = mlc.getPlaceholderString(new String[]{"skill", "s", "ondamagedskill", "ondamaged", "od", "onhitskill", "onhit", "oh", "meta", "m", "mechanics", "$", "()"}, "skill not found");
|
||||
weaponTypes = mlc.getString(new String[]{"weapons", "weapon", "w"}, "MUSKET");
|
||||
metaskill = GetSkill(skillName.get());
|
||||
cancelEvent = mlc.getBoolean(new String[]{"cancelevent", "ce"}, false);
|
||||
|
||||
// Parse weapon types
|
||||
ArrayList<String> weaponTypesUnparsed = new ArrayList<>();
|
||||
if (weaponTypes.contains(",")) { weaponTypesUnparsed.addAll(Arrays.asList(weaponTypes.split(","))); } else { weaponTypesUnparsed.add(weaponTypes); }
|
||||
|
||||
for (String weapon : weaponTypesUnparsed) {
|
||||
// Try to get
|
||||
try {
|
||||
|
||||
// Parse
|
||||
UseItemTypes weap = UseItemTypes.valueOf(weapon.toUpperCase());
|
||||
|
||||
// Yes
|
||||
auraWeapons.add(weap);
|
||||
|
||||
} catch (IllegalArgumentException ignored) {}
|
||||
}
|
||||
|
||||
// Attempt to fix meta skill
|
||||
if (metaskill == null) {
|
||||
//MM//OotilityCeption.Log("\u00a7c--->> \u00a7eMeta Skill Failure \u00a7c<<---");
|
||||
|
||||
// Try again i guess?
|
||||
(new BukkitRunnable() {
|
||||
public void run() {
|
||||
|
||||
// Run Async
|
||||
metaskill = GetSkill(skillName.get());
|
||||
|
||||
}
|
||||
}).runTaskLater(MMOItems.plugin, 1L);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean castAtEntity(SkillMetadata data, AbstractEntity target) {
|
||||
// Find caster
|
||||
SkillCaster caster;
|
||||
|
||||
// Will be caster of the skill, as a mythicmob
|
||||
if (MythicMobs.inst().getMobManager().isActiveMob(target)) {
|
||||
//SOM//OotilityCeption.Log("\u00a73 * \u00a77Target as ActiveMob");
|
||||
|
||||
// Just pull the mythicmob
|
||||
caster = MythicMobs.inst().getMobManager().getMythicMobInstance(target);
|
||||
|
||||
// If its a player or some other non-mythicmob
|
||||
} else {
|
||||
//SOM//OotilityCeption.Log("\u00a73 * \u00a77Target as Non MM");
|
||||
|
||||
// I guess make a new caster out of them
|
||||
caster = new GenericCaster(target);
|
||||
}
|
||||
|
||||
new MMOItemsOnShootAura.Tracker(caster, data, target);
|
||||
return true;
|
||||
}
|
||||
|
||||
private class Tracker extends AuraTracker implements IParentSkill, Runnable {
|
||||
public Tracker(SkillCaster caster, SkillMetadata data, AbstractEntity entity) {
|
||||
super(caster, entity, data);
|
||||
this.start();
|
||||
}
|
||||
|
||||
public void auraStart() {
|
||||
this.registerAuraComponent(Events.subscribe(MMOItemsSpecialWeaponAttack.class).filter((event) -> {
|
||||
|
||||
//SOM//OotilityCeption.Log("\u00a7cStep 3 \u00a77Subscribe Run: " + getName(event.getEntity()) + "\u00a77 vs " + getName(this.entity.get()) + "\u00a78 ~\u00a7e " + event.getEntity().getUniqueId().equals(this.entity.get().getUniqueId()));
|
||||
|
||||
// Player is the one who has the aura applied, right?
|
||||
if (!event.getPlayer().getUniqueId().equals(this.entity.get().getUniqueId())) { return false; }
|
||||
|
||||
// All custom weapons fire it if none specified.
|
||||
if (auraWeapons.size() == 0) { return true; }
|
||||
|
||||
// Okay go through all weapon types, must match one
|
||||
for (UseItemTypes weap : auraWeapons) {
|
||||
if (weap.getInst().isInstance(event.getWeapon())) { return true; } }
|
||||
|
||||
// None matched
|
||||
return false;
|
||||
|
||||
}).handler((event) -> {
|
||||
|
||||
// Clone metadata
|
||||
SkillMetadata meta = this.skillMetadata.deepClone();
|
||||
|
||||
// Refresh
|
||||
if (metaskill == null) { metaskill = GetSkill(skillName.get(meta, meta.getCaster().getEntity())); }
|
||||
|
||||
// Target obviously the projectile
|
||||
AbstractEntity target = BukkitAdapter.adapt(event.getTarget());
|
||||
meta.setTrigger(target);
|
||||
|
||||
//SOM//OotilityCeption.Log("\u00a7cStep 4 \u00a77Aura Run:\u00a7d " + logSkillData(meta) + "\u00a7b " + metaskill.getInternalName());
|
||||
if (this.executeAuraSkill(Optional.ofNullable(metaskill), meta)) {
|
||||
|
||||
this.consumeCharge();
|
||||
|
||||
if (cancelEvent) { event.setCancelled(true); }
|
||||
}
|
||||
|
||||
}));
|
||||
this.executeAuraSkill(MMOItemsOnShootAura.this.onStartSkill, this.skillMetadata);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable public static Skill GetSkill(String skillName) {
|
||||
|
||||
if (SkillExists(skillName)) {
|
||||
|
||||
Optional<Skill> mSkillFk = MythicMobs.inst().getSkillManager().getSkill(skillName);
|
||||
if (mSkillFk == null) { return null; }
|
||||
if (mSkillFk.isPresent()) { return mSkillFk.get(); }
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
public static boolean SkillExists(String skillName) {
|
||||
// If null no
|
||||
if (skillName == null) { return false; }
|
||||
|
||||
Optional<Skill> mSkillFk = MythicMobs.inst().getSkillManager().getSkill(skillName);
|
||||
|
||||
// Is there a skill of that name?
|
||||
if (mSkillFk.isPresent()) {
|
||||
|
||||
try {
|
||||
// Ok then retrieve the skill
|
||||
Skill mSkill = (Skill) mSkillFk.get();
|
||||
|
||||
// Success
|
||||
return true;
|
||||
|
||||
} catch (Exception e) {
|
||||
|
||||
// RIP
|
||||
return false;
|
||||
}
|
||||
|
||||
// The skill was not found
|
||||
} else {
|
||||
|
||||
// False means the skill does not exist.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
enum UseItemTypes {
|
||||
CROSSBOW(Crossbow.class),
|
||||
GAUNTLET(Gauntlet.class),
|
||||
LUTE(Lute.class),
|
||||
MUSKET(Musket.class),
|
||||
STAFF(Staff.class),
|
||||
WHIP(Whip.class);
|
||||
|
||||
/**
|
||||
* @return Class to use InstanceOf and identify a weapon.
|
||||
*/
|
||||
@NotNull public Class getInst() { return inst; }
|
||||
@NotNull final Class inst;
|
||||
UseItemTypes(@NotNull Class inst) {
|
||||
this.inst = inst;
|
||||
}
|
||||
}
|
||||
}
|
@ -20,6 +20,7 @@ import org.bukkit.event.inventory.InventoryClickEvent;
|
||||
import org.bukkit.inventory.Inventory;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@ -40,6 +41,7 @@ public class CraftingStationPreview extends PluginInventory {
|
||||
this.recipe = recipe;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Inventory getInventory() {
|
||||
|
||||
@ -105,8 +107,8 @@ public class CraftingStationPreview extends PluginInventory {
|
||||
inv.setItem(slot, ConfigItems.FILL.getItem());
|
||||
|
||||
if (recipe.getRecipe() instanceof CraftingRecipe) {
|
||||
ItemStack item = ((CraftingRecipe) recipe.getRecipe()).getOutput().getPreview();
|
||||
item.setAmount(((CraftingRecipe) recipe.getRecipe()).getOutput().getAmount());
|
||||
ItemStack item = ((CraftingRecipe) recipe.getRecipe()).getPreviewItemStack();
|
||||
item.setAmount(((CraftingRecipe) recipe.getRecipe()).getOutputAmount());
|
||||
inv.setItem(16, item);
|
||||
}
|
||||
if (recipe.getRecipe() instanceof UpgradingRecipe) {
|
||||
|
@ -181,7 +181,7 @@ public class CraftingStationView extends PluginInventory {
|
||||
* to the player and remove the recipe from the queue
|
||||
*/
|
||||
if (recipeInfo.isReady()) {
|
||||
ItemStack result = recipe.hasOption(Recipe.RecipeOption.OUTPUT_ITEM) ? recipe.getOutput().generate(playerData.getRPG()) : null;
|
||||
ItemStack result = recipe.hasOption(Recipe.RecipeOption.OUTPUT_ITEM) ? recipe.getOutputItemStack(playerData.getRPG()) : null;
|
||||
|
||||
PlayerUseCraftingStationEvent called = new PlayerUseCraftingStationEvent(playerData, station, recipe, result);
|
||||
Bukkit.getPluginManager().callEvent(called);
|
||||
|
@ -69,7 +69,7 @@ public class AbilityEdition extends EditionInventory {
|
||||
if (ability != null) {
|
||||
String castModeConfigString = getEditedSection().getString("ability." + configKey + ".mode");
|
||||
String castModeFormat = castModeConfigString == null ? ""
|
||||
: castModeConfigString.toUpperCase().replace(" ", "_").replace("-", "_").replaceAll("[^A-Z_]", "");
|
||||
: castModeConfigString.toUpperCase().replace(" ", "_").replace("-", "_").replaceAll("[^A-Z0-9_]", "");
|
||||
TriggerType castMode = TriggerType.safeValueOf(castModeFormat);
|
||||
|
||||
ItemStack castModeItem = new ItemStack(Material.ARMOR_STAND);
|
||||
|
@ -12,6 +12,8 @@ import net.Indyuce.mmoitems.MMOUtils;
|
||||
import net.Indyuce.mmoitems.api.ItemAttackMetadata;
|
||||
import net.Indyuce.mmoitems.api.Type;
|
||||
import net.Indyuce.mmoitems.api.TypeSet;
|
||||
import net.Indyuce.mmoitems.api.event.MMOItemsProjectileFireEvent;
|
||||
import net.Indyuce.mmoitems.api.event.MMOItemsSpecialWeaponAttack;
|
||||
import net.Indyuce.mmoitems.api.interaction.*;
|
||||
import net.Indyuce.mmoitems.api.interaction.weapon.Gauntlet;
|
||||
import net.Indyuce.mmoitems.api.interaction.weapon.Weapon;
|
||||
@ -20,6 +22,7 @@ import net.Indyuce.mmoitems.api.interaction.weapon.untargeted.UntargetedWeapon;
|
||||
import net.Indyuce.mmoitems.api.interaction.weapon.untargeted.UntargetedWeapon.WeaponType;
|
||||
import net.Indyuce.mmoitems.api.player.PlayerData;
|
||||
import net.Indyuce.mmoitems.api.util.message.Message;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.GameMode;
|
||||
import org.bukkit.Material;
|
||||
@ -95,12 +98,23 @@ public class ItemUse implements Listener {
|
||||
}
|
||||
|
||||
if (useItem instanceof UntargetedWeapon) {
|
||||
|
||||
UntargetedWeapon weapon = (UntargetedWeapon) useItem;
|
||||
if ((event.getAction().name().contains("RIGHT_CLICK") && weapon.getWeaponType() == WeaponType.RIGHT_CLICK)
|
||||
|| (event.getAction().name().contains("LEFT_CLICK") && weapon.getWeaponType() == WeaponType.LEFT_CLICK))
|
||||
|| (event.getAction().name().contains("LEFT_CLICK") && weapon.getWeaponType() == WeaponType.LEFT_CLICK)) {
|
||||
MMOItems.log("Running from \u00a7cUNTARGETTED");
|
||||
|
||||
// Run attack event
|
||||
MMOItemsSpecialWeaponAttack attackEvent = new MMOItemsSpecialWeaponAttack(player, useItem, weapon.untargetedTargetTrace(EquipmentSlot.fromBukkit(event.getHand())));
|
||||
Bukkit.getPluginManager().callEvent(attackEvent);
|
||||
|
||||
// Cancelled?
|
||||
if (attackEvent.isCancelled()) { return; }
|
||||
|
||||
weapon.untargetedAttack(EquipmentSlot.fromBukkit(event.getHand()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(ignoreCancelled = true)
|
||||
public void meleeAttacks(PlayerAttackEvent event) {
|
||||
@ -186,13 +200,34 @@ public class ItemUse implements Listener {
|
||||
return;
|
||||
|
||||
// Special staff attack
|
||||
if (weapon instanceof Staff)
|
||||
if (weapon instanceof Staff) {
|
||||
MMOItems.log("Running from \u00a7aSTAFF");
|
||||
// Run attack event
|
||||
MMOItemsSpecialWeaponAttack attackEvent = new MMOItemsSpecialWeaponAttack(player, weapon, target);
|
||||
Bukkit.getPluginManager().callEvent(attackEvent);
|
||||
|
||||
// Cancelled?
|
||||
if (attackEvent.isCancelled()) { return; }
|
||||
|
||||
// Run attack
|
||||
((Staff) weapon).specialAttack(target);
|
||||
}
|
||||
|
||||
// Special gauntlet attack
|
||||
if (weapon instanceof Gauntlet)
|
||||
if (weapon instanceof Gauntlet) {
|
||||
MMOItems.log("Running from \u00a7bGAUNTLET");
|
||||
|
||||
// Run attack event
|
||||
MMOItemsSpecialWeaponAttack attackEvent = new MMOItemsSpecialWeaponAttack(player, weapon, target);
|
||||
Bukkit.getPluginManager().callEvent(attackEvent);
|
||||
|
||||
// Cancelled?
|
||||
if (attackEvent.isCancelled()) { return; }
|
||||
|
||||
// Run attack
|
||||
((Gauntlet) weapon).specialAttack(target);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Rewrite this with a custom 'ApplyMMOItemEvent'?
|
||||
@EventHandler
|
||||
@ -289,8 +324,7 @@ public class ItemUse implements Listener {
|
||||
Arrow arrow = (Arrow) event.getProjectile();
|
||||
if (item.getStat("ARROW_VELOCITY") > 0)
|
||||
arrow.setVelocity(arrow.getVelocity().multiply(item.getStat("ARROW_VELOCITY")));
|
||||
MMOItems.plugin.getEntities().registerCustomProjectile(item, playerData.getStats().newTemporary(bowSlot), event.getProjectile(), type != null,
|
||||
event.getForce());
|
||||
MMOItems.plugin.getEntities().registerCustomProjectile(item, playerData.getStats().newTemporary(bowSlot), event.getProjectile(), event, type != null, event.getForce());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -22,6 +22,7 @@ import org.bukkit.Material;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
import org.bukkit.potion.PotionEffectType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
@ -255,8 +256,8 @@ public class ConfigManager implements Reloadable {
|
||||
return configName != null ? configName : ability.getName();
|
||||
}
|
||||
|
||||
public String getCastingModeName(TriggerType mode) {
|
||||
return abilities.getConfig().getString("cast-mode." + mode.getLowerCaseId());
|
||||
@NotNull public String getCastingModeName(@NotNull TriggerType mode) {
|
||||
return abilities.getConfig().getString("cast-mode." + mode.getLowerCaseId(), mode.name());
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
|
@ -6,6 +6,7 @@ import io.lumine.mythic.lib.damage.DamageType;
|
||||
import io.lumine.mythic.lib.player.PlayerMetadata;
|
||||
import net.Indyuce.mmoitems.MMOItems;
|
||||
import net.Indyuce.mmoitems.api.ItemAttackMetadata;
|
||||
import net.Indyuce.mmoitems.api.event.MMOItemsProjectileFireEvent;
|
||||
import net.Indyuce.mmoitems.api.interaction.projectile.ArrowParticles;
|
||||
import net.Indyuce.mmoitems.api.interaction.projectile.EntityData;
|
||||
import net.Indyuce.mmoitems.api.interaction.projectile.ProjectileData;
|
||||
@ -20,6 +21,9 @@ import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.entity.EntityDamageByEntityEvent;
|
||||
import org.bukkit.event.entity.EntityDeathEvent;
|
||||
import org.bukkit.event.entity.EntityShootBowEvent;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
@ -36,10 +40,8 @@ public class EntityManager implements Listener {
|
||||
|
||||
private final WeakHashMap<Integer, ProjectileData> projectiles = new WeakHashMap<>();
|
||||
|
||||
public void registerCustomProjectile(NBTItem sourceItem, PlayerMetadata attacker, Entity entity, boolean customWeapon) {
|
||||
registerCustomProjectile(sourceItem, attacker, entity, customWeapon, 1);
|
||||
}
|
||||
|
||||
@Deprecated public void registerCustomProjectile(NBTItem sourceItem, PlayerMetadata attacker, Entity entity, boolean customWeapon) { registerCustomProjectile(sourceItem, attacker, entity, customWeapon, 1); }
|
||||
@Deprecated public void registerCustomProjectile(@NotNull NBTItem sourceItem, @NotNull PlayerMetadata attacker, @NotNull Entity entity, boolean customWeapon, double damageMultiplicator) { registerCustomProjectile(sourceItem, attacker, entity, null, customWeapon, damageMultiplicator); }
|
||||
/**
|
||||
* Registers a custom projectile. This is used for bows, crossbows and tridents.
|
||||
* <p>
|
||||
@ -47,12 +49,13 @@ public class EntityManager implements Listener {
|
||||
*
|
||||
* @param sourceItem Item used to shoot the projectile
|
||||
* @param attacker Cached stats of the player shooting the projectile
|
||||
* @param shootEvent Event that caused this projectile registration.
|
||||
* @param entity The custom entity
|
||||
* @param customWeapon Is the source weapon is a custom item
|
||||
* @param damageMultiplicator The damage coefficient. For bows, this is basically the pull force.
|
||||
* For tridents or anything else this is always set to 1
|
||||
*/
|
||||
public void registerCustomProjectile(NBTItem sourceItem, PlayerMetadata attacker, Entity entity, boolean customWeapon, double damageMultiplicator) {
|
||||
public void registerCustomProjectile(@NotNull NBTItem sourceItem, @NotNull PlayerMetadata attacker, @NotNull Entity entity, @Nullable EntityShootBowEvent shootEvent, boolean customWeapon, double damageMultiplicator) {
|
||||
|
||||
/*
|
||||
* For bows, MC default value is 7. When using custom bows, the attack
|
||||
@ -64,10 +67,16 @@ public class EntityManager implements Listener {
|
||||
* and 1 for bows, and it's always 1 for tridents or crossbows.
|
||||
*/
|
||||
double damage = attacker.getStat("ATTACK_DAMAGE");
|
||||
damage = (customWeapon ? damage : 5 + damage) * damageMultiplicator;
|
||||
|
||||
ItemAttackMetadata attackMeta = new ItemAttackMetadata(new DamageMetadata(damage, DamageType.WEAPON, DamageType.PHYSICAL, DamageType.PROJECTILE), attacker);
|
||||
attacker.setStat("ATTACK_DAMAGE", damage);
|
||||
// Sweet event
|
||||
MMOItemsProjectileFireEvent event = new MMOItemsProjectileFireEvent(attacker, entity, sourceItem, shootEvent, (customWeapon ? damage : 5 + damage), damageMultiplicator);
|
||||
Bukkit.getPluginManager().callEvent(event);
|
||||
|
||||
// Update based one vent
|
||||
double finalDamage = event.getFinalDamage();
|
||||
|
||||
ItemAttackMetadata attackMeta = new ItemAttackMetadata(new DamageMetadata(finalDamage, event.getDamageTypes()), attacker);
|
||||
attacker.setStat("ATTACK_DAMAGE", finalDamage);
|
||||
|
||||
/*
|
||||
* Load arrow particles if the entity is an arrow and if the item has
|
||||
|
@ -113,7 +113,8 @@ public class Abilities extends ItemStat {
|
||||
String configKey = (String) info[0];
|
||||
String edited = (String) info[1];
|
||||
|
||||
String format = message.toUpperCase().replace("-", "_").replace(" ", "_").replaceAll("[^A-Z_]", "");
|
||||
String format = message.toUpperCase().replace("-", "_").replace(" ", "_").replaceAll("[^A-Z0-9_]", "");
|
||||
|
||||
if (edited.equals("ability")) {
|
||||
Validate.isTrue(MMOItems.plugin.getSkills().hasSkill(format),
|
||||
"format is not a valid ability! You may check the ability list using /mi list ability.");
|
||||
@ -128,7 +129,9 @@ public class Abilities extends ItemStat {
|
||||
}
|
||||
|
||||
if (edited.equals("mode")) {
|
||||
|
||||
TriggerType castMode = TriggerType.valueOf(format);
|
||||
|
||||
inv.getEditedSection().set("ability." + configKey + ".mode", castMode.name());
|
||||
inv.registerTemplateEdition();
|
||||
inv.getPlayer().sendMessage(MMOItems.plugin.getPrefix() + "Successfully set the trigger to " + ChatColor.GOLD + castMode.getName()
|
||||
|
@ -28,8 +28,8 @@ import java.util.Set;
|
||||
|
||||
public class AbilityData extends Skill {
|
||||
private final RegisteredSkill ability;
|
||||
private final TriggerType triggerType;
|
||||
private final Map<String, Double> modifiers = new HashMap<>();
|
||||
@NotNull private final TriggerType triggerType;
|
||||
@NotNull private final Map<String, Double> modifiers = new HashMap<>();
|
||||
|
||||
public AbilityData(JsonObject object) {
|
||||
ability = MMOItems.plugin.getSkills().getSkill(object.get("Id").getAsString());
|
||||
@ -63,9 +63,7 @@ public class AbilityData extends Skill {
|
||||
return ability;
|
||||
}
|
||||
|
||||
public TriggerType getTriggerType() {
|
||||
return triggerType;
|
||||
}
|
||||
@NotNull public TriggerType getTriggerType() { return triggerType; }
|
||||
|
||||
public Set<String> getModifiers() {
|
||||
return modifiers.keySet();
|
||||
@ -80,7 +78,6 @@ public class AbilityData extends Skill {
|
||||
return modifiers.containsKey(path);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public boolean getResult(SkillMetadata meta) {
|
||||
|
||||
|
@ -98,6 +98,14 @@ lore-format:
|
||||
- '#repair-percent#'
|
||||
- '#item-cooldown#'
|
||||
- '#additional-experience#'
|
||||
- '#additional-experience-alchemy#'
|
||||
- '#additional-experience-enchanting#'
|
||||
- '#additional-experience-farming#'
|
||||
- '#additional-experience-fishing#'
|
||||
- '#additional-experience-mining#'
|
||||
- '#additional-experience-smelting#'
|
||||
- '#additional-experience-smithing#'
|
||||
- '#additional-experience-woodcutting#'
|
||||
- '#cooldown-reduction#'
|
||||
- '#mana-cost#'
|
||||
- '#stamina-cost#'
|
||||
|
@ -64,6 +64,14 @@ max-stamina: '&3 &7■ Max Stamina: &f<plus>#'
|
||||
stamina-regeneration: '&3 &7■ Stamina Regeneration: &f<plus>#'
|
||||
cooldown-reduction: '&3 &7■ Skill Cooldown Reduction: &f<plus>#%'
|
||||
additional-experience: '&3 &7■ Additional Experience: &f<plus>#%'
|
||||
additional-experience-alchemy: '&7■ Additional Alchemy Experience: &f<plus>#%'
|
||||
additional-experience-enchanting: '&7■ Additional Enchanting Experience: &f<plus>#%'
|
||||
additional-experience-farming: '&7■ Additional Farming Experience: &f<plus>#%'
|
||||
additional-experience-fishing: '&7■ Additional Fishing Experience: &f<plus>#%'
|
||||
additional-experience-mining: '&7■ Additional Mining Experience: &f<plus>#%'
|
||||
additional-experience-smelting: '&7■ Additional Smelting Experience: &f<plus>#%'
|
||||
additional-experience-smithing: '&7■ Additional Smithing Experience: &f<plus>#%'
|
||||
additional-experience-woodcutting: '&7■ Additional Woodcutting Experience: &f<plus>#%'
|
||||
|
||||
# Extra Options
|
||||
perm-effect: '&3 &7■ Permanent &f#'
|
||||
|
Loading…
Reference in New Issue
Block a user