mirror of
https://gitlab.com/phoenix-dvpmt/mmoitems.git
synced 2025-01-10 07:47:35 +01:00
Merge branch 'custom_item_types'
This commit is contained in:
commit
1fabd75d10
@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>MMOItems</artifactId>
|
||||
<groupId>net.Indyuce</groupId>
|
||||
<version>6.9.5-SNAPSHOT</version>
|
||||
<version>6.10-SNAPSHOT</version>
|
||||
</parent>
|
||||
<packaging>jar</packaging>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
@ -51,10 +51,14 @@ public class ItemStats {
|
||||
DISABLE_ENCHANTING = new DisableStat("ENCHANTING", VersionMaterial.ENCHANTING_TABLE.toMaterial(), "Disable Enchanting", new String[]{"!block", "all"}, "Players can't enchant this item."),
|
||||
DISABLE_REPAIRING = new DisableStat("REPAIRING", Material.ANVIL, "Disable Repairing", new String[]{"!block", "all"}, "Players can't use this item in anvils."),
|
||||
DISABLE_ARROW_SHOOTING = new DisableStat("ARROW_SHOOTING", Material.ARROW, "Disable Arrow Shooting", new Material[]{Material.ARROW}, "Players can't shoot this", "item using a bow."),
|
||||
DISABLE_ATTACK_PASSIVE = new DisableStat("ATTACK_PASSIVE", Material.BARRIER, "Disable Attack Passive", new String[]{"piercing", "slashing", "blunt"}, "Disables the blunt/slashing/piercing", "passive effects on attacks."),
|
||||
DISABLE_DROP = new DisableStat("DROPING", Material.LAVA_BUCKET, "Disable Item Dropping", new String[]{"all"}, "Disables the dropping of this item!"),
|
||||
DISABLE_ARROW_CONSUMPTION = new DisableStat("ARROW_CONSUMPTION", Material.ARROW, "Disable Arrow Consumption", new String[]{"crossbow"}, "Disable arrow requirement and consumption."),
|
||||
|
||||
// Special item interactions/skills
|
||||
LEFT_CLICK_SCRIPT = new ActionLeftClick(),
|
||||
RIGHT_CLICK_SCRIPT = new ActionRightClick(),
|
||||
DISABLE_ATTACK_PASSIVE = new DisableStat("ATTACK_PASSIVE", Material.BARRIER, "Disable On-Hit Effect", new String[]{"weapon"}, "Disables on-hit effects granted by the item type."),
|
||||
|
||||
// RPG Stats
|
||||
REQUIRED_LEVEL = new RequiredLevel(),
|
||||
REQUIRED_CLASS = new RequiredClass(),
|
||||
@ -74,11 +78,11 @@ public class ItemStats {
|
||||
COOLDOWN_REDUCTION = new DoubleStat("COOLDOWN_REDUCTION", Material.BOOK, "Cooldown Reduction", new String[]{"Reduces cooldowns of item and player skills (%)."}),
|
||||
RANGE = new DoubleStat("RANGE", Material.STICK, "Range", new String[]{"The range of your item attacks."}, new String[]{"staff", "whip", "wand", "musket", "gem_stone"}),
|
||||
MANA_COST = new ManaCost(),
|
||||
STAMINA_COST = new DoubleStat("STAMINA_COST", VersionMaterial.LIGHT_GRAY_DYE.toMaterial(), "Stamina Cost", new String[]{"Stamina spent by your weapon to be used."}, new String[]{"piercing", "slashing", "blunt", "range"}),
|
||||
STAMINA_COST = new DoubleStat("STAMINA_COST", VersionMaterial.LIGHT_GRAY_DYE.toMaterial(), "Stamina Cost", new String[]{"Stamina spent by your weapon to be used."}, new String[]{"weapon"}),
|
||||
ARROW_VELOCITY = new DoubleStat("ARROW_VELOCITY", Material.ARROW, "Arrow Velocity", new String[]{"Determines how far your", "weapon can shoot.", "Default: 1.0"}, new String[]{"gem_stone", "bow", "crossbow"}),
|
||||
ARROW_POTION_EFFECTS = new ArrowPotionEffects(),
|
||||
PVE_DAMAGE = new DoubleStat("PVE_DAMAGE", VersionMaterial.PORKCHOP.toMaterial(), "PvE Damage", new String[]{"Additional damage against", "non human entities in %."}, new String[]{"piercing", "slashing", "blunt", "catalyst", "range", "tool", "armor", "gem_stone", "accessory"}),
|
||||
PVP_DAMAGE = new DoubleStat("PVP_DAMAGE", VersionMaterial.SKELETON_SKULL.toMaterial(), "PvP Damage", new String[]{"Additional damage", "against players in %."}, new String[]{"piercing", "slashing", "blunt", "catalyst", "range", "tool", "armor", "gem_stone", "accessory"}),
|
||||
PVE_DAMAGE = new DoubleStat("PVE_DAMAGE", VersionMaterial.PORKCHOP.toMaterial(), "PvE Damage", new String[]{"Additional damage against", "non human entities in %."}, new String[]{"weapon", "catalyst", "tool", "armor", "gem_stone", "accessory"}),
|
||||
PVP_DAMAGE = new DoubleStat("PVP_DAMAGE", VersionMaterial.SKELETON_SKULL.toMaterial(), "PvP Damage", new String[]{"Additional damage", "against players in %."}, new String[]{"weapon", "catalyst", "tool", "armor", "gem_stone", "accessory"}),
|
||||
BLUNT_POWER = new DoubleStat("BLUNT_POWER", Material.IRON_AXE, "Blunt Power", new String[]{"The radius of the AoE attack.", "If set to 2.0, enemies within 2 blocks", "around your target will take damage."}, new String[]{"blunt", "gem_stone"}),
|
||||
BLUNT_RATING = new DoubleStat("BLUNT_RATING", Material.BRICK, "Blunt Rating", new String[]{"The force of the blunt attack.", "If set to 50%, enemies hit by the attack", "will take 50% of the initial damage."}, new String[]{"blunt", "gem_stone"}),
|
||||
WEAPON_DAMAGE = new DoubleStat("WEAPON_DAMAGE", Material.IRON_SWORD, "Weapon Damage", new String[]{"Additional on-hit weapon damage in %."}),
|
||||
@ -110,7 +114,7 @@ public class ItemStats {
|
||||
MAX_MANA = new DoubleStat("MAX_MANA", VersionMaterial.LAPIS_LAZULI.toMaterial(), "Max Mana", new String[]{"Adds mana to your max mana bar."}),
|
||||
KNOCKBACK_RESISTANCE = new KnockbackResistance(),
|
||||
MOVEMENT_SPEED = new MovementSpeed(),
|
||||
TWO_HANDED = new BooleanStat("TWO_HANDED", Material.IRON_INGOT, "Two Handed", new String[]{"If set to true, a player will be", "significantly slower if holding two", "items, one being Two Handed."}, new String[]{"piercing", "slashing", "blunt", "catalyst", "range", "tool"}),
|
||||
TWO_HANDED = new BooleanStat("TWO_HANDED", Material.IRON_INGOT, "Two Handed", new String[]{"If set to true, a player will be", "significantly slower if holding two", "items, one being Two Handed."}, new String[]{"weapon", "catalyst", "tool"}),
|
||||
REQUIRED_BIOMES = new RequiredBiomes(),
|
||||
DROP_ON_DEATH = new DisableDeathDrop(),
|
||||
DURABILITY_BAR = new DurabilityBar(),
|
||||
@ -154,8 +158,8 @@ public class ItemStats {
|
||||
CUSTOM_SOUNDS = new CustomSounds(),
|
||||
ELEMENTS = new Elements(),
|
||||
COMMANDS = new Commands(),
|
||||
STAFF_SPIRIT = new StaffSpiritStat(),
|
||||
LUTE_ATTACK_SOUND = new LuteAttackSoundStat(),
|
||||
// STAFF_SPIRIT = new StaffSpiritStat(),
|
||||
LUTE_ATTACK_SOUND = new LuteAttackSoundStat(),
|
||||
LUTE_ATTACK_EFFECT = new LuteAttackEffectStat(),
|
||||
NOTE_WEIGHT = new DoubleStat("NOTE_WEIGHT", VersionMaterial.MUSIC_DISC_MALL.toMaterial(), "Note Weight", new String[]{"Defines how the projectile cast", "by your lute tilts downwards."}, new String[]{"lute"}),
|
||||
REMOVE_ON_CRAFT = new BooleanStat("REMOVE_ON_CRAFT", Material.GLASS_BOTTLE, "Remove on Craft", new String[]{"If the item should be completely", "removed when used in a recipe,", "or if it should become an", "empty bottle or bucket."}, new String[]{"all"}, Material.POTION, Material.SPLASH_POTION, Material.LINGERING_POTION, Material.MILK_BUCKET, Material.LAVA_BUCKET, Material.WATER_BUCKET),
|
||||
@ -178,8 +182,8 @@ 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", "catalyst", "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", "catalyst", "range", "tool", "armor", "consumable", "accessory"}),
|
||||
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[]{"weapon", "catalyst", "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[]{"weapon", "catalyst", "tool", "armor", "consumable", "accessory"}),
|
||||
DOWNGRADE_ON_DEATH_CHANCE = new DoubleStat("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"}, false),
|
||||
|
||||
// Unique Item Stats
|
||||
@ -203,7 +207,7 @@ public class ItemStats {
|
||||
|
||||
/**
|
||||
* @deprecated Item damage is now {@link ItemDamage} and
|
||||
* custom durability is now {@link CustomDurability}
|
||||
* custom durability is now {@link CustomDurability}
|
||||
*/
|
||||
@Deprecated
|
||||
public static final ItemStat DURABILITY = ITEM_DAMAGE;
|
||||
|
@ -4,8 +4,8 @@ import io.lumine.mythic.lib.api.item.NBTItem;
|
||||
import io.lumine.mythic.lib.api.util.ui.FriendlyFeedbackMessage;
|
||||
import io.lumine.mythic.lib.api.util.ui.FriendlyFeedbackProvider;
|
||||
import io.lumine.mythic.lib.version.SpigotPlugin;
|
||||
import net.Indyuce.mmoitems.api.ItemTier;
|
||||
import net.Indyuce.mmoitems.api.DeathItemsHandler;
|
||||
import net.Indyuce.mmoitems.api.ItemTier;
|
||||
import net.Indyuce.mmoitems.api.Type;
|
||||
import net.Indyuce.mmoitems.api.crafting.MMOItemUIFilter;
|
||||
import net.Indyuce.mmoitems.api.item.mmoitem.MMOItem;
|
||||
@ -68,7 +68,6 @@ public class MMOItems extends JavaPlugin {
|
||||
private final LoreFormatManager loreManager = new LoreFormatManager();
|
||||
private final TemplateManager templateManager = new TemplateManager();
|
||||
private final SkillManager skillManager = new SkillManager();
|
||||
private final EntityManager entityManager = new EntityManager();
|
||||
private final RecipeManager recipeManager = new RecipeManager();
|
||||
private final LayoutManager layoutManager = new LayoutManager();
|
||||
private final TypeManager typeManager = new TypeManager();
|
||||
@ -120,7 +119,7 @@ public class MMOItems extends JavaPlugin {
|
||||
configManager = new ConfigManager();
|
||||
|
||||
statManager.load();
|
||||
typeManager.reload();
|
||||
typeManager.reload(false);
|
||||
templateManager.preloadObjects();
|
||||
|
||||
PluginUtils.isDependencyPresent("MMOCore", u -> new MMOCoreMMOLoader());
|
||||
@ -141,6 +140,8 @@ public class MMOItems extends JavaPlugin {
|
||||
MMOItemUIFilter.register();
|
||||
RecipeTypeListGUI.registerNativeRecipes();
|
||||
|
||||
typeManager.postload();
|
||||
|
||||
skillManager.initialize(false);
|
||||
|
||||
final int configVersion = getConfig().contains("config-version", true) ? getConfig().getInt("config-version") : -1;
|
||||
@ -185,7 +186,6 @@ public class MMOItems extends JavaPlugin {
|
||||
// This ones are not implementing Reloadable
|
||||
MMOItemReforger.reload();
|
||||
|
||||
Bukkit.getPluginManager().registerEvents(entityManager, this);
|
||||
Bukkit.getPluginManager().registerEvents(dropTableManager, this);
|
||||
|
||||
// Load Dist module
|
||||
@ -410,10 +410,10 @@ public class MMOItems extends JavaPlugin {
|
||||
*
|
||||
* @param value The player inventory subclass
|
||||
* @deprecated Rather than setting this to the only inventory MMOItems will
|
||||
* search equipment within, you must add your inventory to the
|
||||
* handler with <code>getInventory().register()</code>. This method
|
||||
* will clear all other PlayerInventories for now, as to keep
|
||||
* backwards compatibility.
|
||||
* search equipment within, you must add your inventory to the
|
||||
* handler with <code>getInventory().register()</code>. This method
|
||||
* will clear all other PlayerInventories for now, as to keep
|
||||
* backwards compatibility.
|
||||
*/
|
||||
@Deprecated
|
||||
public void setPlayerInventory(PlayerInventory value) {
|
||||
@ -450,10 +450,6 @@ public class MMOItems extends JavaPlugin {
|
||||
return tierManager;
|
||||
}
|
||||
|
||||
public EntityManager getEntities() {
|
||||
return entityManager;
|
||||
}
|
||||
|
||||
public DropTableManager getDropTables() {
|
||||
return dropTableManager;
|
||||
}
|
||||
@ -490,7 +486,7 @@ public class MMOItems extends JavaPlugin {
|
||||
return templateManager;
|
||||
}
|
||||
|
||||
public LoreFormatManager getLore(){
|
||||
public LoreFormatManager getLore() {
|
||||
return loreManager;
|
||||
}
|
||||
|
||||
@ -527,9 +523,9 @@ public class MMOItems extends JavaPlugin {
|
||||
|
||||
/**
|
||||
* @return Generates an item given an item template. The item level will
|
||||
* scale according to the player RPG level if the template has the
|
||||
* 'level-item' option. The item will pick a random tier if the
|
||||
* template has the 'tiered' option
|
||||
* scale according to the player RPG level if the template has the
|
||||
* 'level-item' option. The item will pick a random tier if the
|
||||
* template has the 'tiered' option
|
||||
*/
|
||||
@Nullable
|
||||
public MMOItem getMMOItem(@Nullable Type type, @Nullable String id, @Nullable PlayerData player) {
|
||||
@ -547,9 +543,9 @@ public class MMOItems extends JavaPlugin {
|
||||
|
||||
/**
|
||||
* @return Generates an item given an item template. The item level will
|
||||
* scale according to the player RPG level if the template has the
|
||||
* 'level-item' option. The item will pick a random tier if the
|
||||
* template has the 'tiered' option
|
||||
* scale according to the player RPG level if the template has the
|
||||
* 'level-item' option. The item will pick a random tier if the
|
||||
* template has the 'tiered' option
|
||||
*/
|
||||
@Nullable
|
||||
public ItemStack getItem(@Nullable Type type, @Nullable String id, @NotNull PlayerData player) {
|
||||
@ -566,7 +562,7 @@ public class MMOItems extends JavaPlugin {
|
||||
* @param itemLevel The desired item level
|
||||
* @param itemTier The desired item tier, can be null
|
||||
* @return Generates an item given an item template with a
|
||||
* specific item level and item tier
|
||||
* specific item level and item tier
|
||||
*/
|
||||
@Nullable
|
||||
public MMOItem getMMOItem(@Nullable Type type, @Nullable String id, int itemLevel, @Nullable ItemTier itemTier) {
|
||||
@ -586,7 +582,7 @@ public class MMOItems extends JavaPlugin {
|
||||
* @param itemLevel The desired item level
|
||||
* @param itemTier The desired item tier, can be null
|
||||
* @return Generates an item given an item template with a
|
||||
* specific item level and item tier
|
||||
* specific item level and item tier
|
||||
*/
|
||||
@Nullable
|
||||
public ItemStack getItem(@Nullable Type type, @Nullable String id, int itemLevel, @Nullable ItemTier itemTier) {
|
||||
@ -601,10 +597,10 @@ public class MMOItems extends JavaPlugin {
|
||||
|
||||
/**
|
||||
* @return Generates an item given an item template. The item level will be
|
||||
* 0 and the item will have no item tier unless one is specified in
|
||||
* the base item data.
|
||||
* <p></p>
|
||||
* Will return <code>null</code> if such MMOItem does not exist.
|
||||
* 0 and the item will have no item tier unless one is specified in
|
||||
* the base item data.
|
||||
* <p></p>
|
||||
* Will return <code>null</code> if such MMOItem does not exist.
|
||||
*/
|
||||
@Nullable
|
||||
public MMOItem getMMOItem(@Nullable Type type, @Nullable String id) {
|
||||
@ -613,10 +609,10 @@ public class MMOItems extends JavaPlugin {
|
||||
|
||||
/**
|
||||
* @return Generates an item given an item template. The item level will be
|
||||
* 0 and the item will have no item tier unless one is specified in
|
||||
* the base item data.
|
||||
* <p></p>
|
||||
* Will return <code>null</code> if such MMOItem does not exist.
|
||||
* 0 and the item will have no item tier unless one is specified in
|
||||
* the base item data.
|
||||
* <p></p>
|
||||
* Will return <code>null</code> if such MMOItem does not exist.
|
||||
*/
|
||||
|
||||
@Nullable
|
||||
@ -629,10 +625,10 @@ public class MMOItems extends JavaPlugin {
|
||||
|
||||
/**
|
||||
* @return Generates an item given an item template. The item level will be
|
||||
* 0 and the item will have no item tier unless one is specified in
|
||||
* the base item data.
|
||||
* <p></p>
|
||||
* Will return <code>null</code> if such MMOItem does not exist.
|
||||
* 0 and the item will have no item tier unless one is specified in
|
||||
* the base item data.
|
||||
* <p></p>
|
||||
* Will return <code>null</code> if such MMOItem does not exist.
|
||||
*/
|
||||
@Nullable
|
||||
public ItemStack getItem(@Nullable Type type, @Nullable String id) {
|
||||
|
@ -3,7 +3,12 @@ package net.Indyuce.mmoitems.api;
|
||||
import io.lumine.mythic.lib.MythicLib;
|
||||
import io.lumine.mythic.lib.UtilityMethods;
|
||||
import io.lumine.mythic.lib.api.item.NBTItem;
|
||||
import io.lumine.mythic.lib.player.cooldown.CooldownObject;
|
||||
import io.lumine.mythic.lib.player.modifier.ModifierSource;
|
||||
import io.lumine.mythic.lib.script.Script;
|
||||
import io.lumine.mythic.lib.skill.handler.SkillHandler;
|
||||
import io.lumine.mythic.lib.util.PostLoadAction;
|
||||
import io.lumine.mythic.lib.util.PreloadedObject;
|
||||
import net.Indyuce.mmoitems.MMOItems;
|
||||
import net.Indyuce.mmoitems.api.item.util.identify.UnidentifiedItem;
|
||||
import net.Indyuce.mmoitems.manager.TypeManager;
|
||||
@ -20,47 +25,46 @@ import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public class Type {
|
||||
public class Type implements CooldownObject, PreloadedObject {
|
||||
|
||||
// Slashing
|
||||
public static final Type SWORD = new Type(TypeSet.SLASHING, "SWORD", true, ModifierSource.MELEE_WEAPON);
|
||||
public static final Type SWORD = new Type("SWORD", true, ModifierSource.MELEE_WEAPON);
|
||||
|
||||
// Piercing
|
||||
public static final Type DAGGER = new Type(TypeSet.PIERCING, "DAGGER", true, ModifierSource.MELEE_WEAPON);
|
||||
public static final Type SPEAR = new Type(TypeSet.PIERCING, "SPEAR", true, ModifierSource.MELEE_WEAPON);
|
||||
public static final Type DAGGER = new Type("DAGGER", true, ModifierSource.MELEE_WEAPON);
|
||||
public static final Type SPEAR = new Type("SPEAR", true, ModifierSource.MELEE_WEAPON);
|
||||
|
||||
// Blunt
|
||||
public static final Type HAMMER = new Type(TypeSet.BLUNT, "HAMMER", true, ModifierSource.MELEE_WEAPON);
|
||||
public static final Type GAUNTLET = new Type(TypeSet.BLUNT, "GAUNTLET", true, ModifierSource.MELEE_WEAPON);
|
||||
public static final Type HAMMER = new Type("HAMMER", true, ModifierSource.MELEE_WEAPON);
|
||||
public static final Type GAUNTLET = new Type("GAUNTLET", true, ModifierSource.MELEE_WEAPON);
|
||||
|
||||
// Range
|
||||
public static final Type WHIP = new Type(TypeSet.RANGE, "WHIP", true, ModifierSource.RANGED_WEAPON);
|
||||
public static final Type STAFF = new Type(TypeSet.RANGE, "STAFF", true, ModifierSource.RANGED_WEAPON);
|
||||
public static final Type BOW = new Type(TypeSet.RANGE, "BOW", true, ModifierSource.RANGED_WEAPON);
|
||||
public static final Type CROSSBOW = new Type(TypeSet.RANGE, "CROSSBOW", false, ModifierSource.RANGED_WEAPON);
|
||||
public static final Type MUSKET = new Type(TypeSet.RANGE, "MUSKET", true, ModifierSource.RANGED_WEAPON);
|
||||
public static final Type LUTE = new Type(TypeSet.RANGE, "LUTE", true, ModifierSource.RANGED_WEAPON);
|
||||
public static final Type WHIP = new Type("WHIP", true, ModifierSource.RANGED_WEAPON);
|
||||
public static final Type STAFF = new Type("STAFF", true, ModifierSource.RANGED_WEAPON);
|
||||
public static final Type BOW = new Type("BOW", true, ModifierSource.RANGED_WEAPON);
|
||||
public static final Type CROSSBOW = new Type("CROSSBOW", true, ModifierSource.RANGED_WEAPON);
|
||||
public static final Type MUSKET = new Type("MUSKET", true, ModifierSource.RANGED_WEAPON);
|
||||
public static final Type LUTE = new Type("LUTE", true, ModifierSource.RANGED_WEAPON);
|
||||
|
||||
// Hand Accessories
|
||||
public static final Type CATALYST = new Type(TypeSet.CATALYST, "CATALYST", false, ModifierSource.HAND_ITEM);
|
||||
public static final Type OFF_CATALYST = new Type(TypeSet.CATALYST, "OFF_CATALYST", false, ModifierSource.OFFHAND_ITEM);
|
||||
public static final Type MAIN_CATALYST = new Type(TypeSet.CATALYST, "MAIN_CATALYST", false, ModifierSource.MAINHAND_ITEM);
|
||||
public static final Type CATALYST = new Type("CATALYST", false, ModifierSource.HAND_ITEM);
|
||||
public static final Type OFF_CATALYST = new Type("OFF_CATALYST", false, ModifierSource.OFFHAND_ITEM);
|
||||
public static final Type MAIN_CATALYST = new Type("MAIN_CATALYST", false, ModifierSource.MAINHAND_ITEM);
|
||||
|
||||
// Any
|
||||
public static final Type ORNAMENT = new Type(TypeSet.EXTRA, "ORNAMENT", false, ModifierSource.VOID);
|
||||
public static final Type ORNAMENT = new Type("ORNAMENT", false, ModifierSource.VOID);
|
||||
|
||||
// Extra
|
||||
public static final Type ARMOR = new Type(TypeSet.EXTRA, "ARMOR", false, ModifierSource.ARMOR);
|
||||
public static final Type TOOL = new Type(TypeSet.EXTRA, "TOOL", false, ModifierSource.MELEE_WEAPON);
|
||||
public static final Type CONSUMABLE = new Type(TypeSet.EXTRA, "CONSUMABLE", false, ModifierSource.MAINHAND_ITEM);
|
||||
public static final Type MISCELLANEOUS = new Type(TypeSet.EXTRA, "MISCELLANEOUS", false, ModifierSource.MAINHAND_ITEM);
|
||||
public static final Type GEM_STONE = new Type(TypeSet.EXTRA, "GEM_STONE", false, ModifierSource.VOID);
|
||||
public static final Type SKIN = new Type(TypeSet.EXTRA, "SKIN", false, ModifierSource.VOID);
|
||||
public static final Type ACCESSORY = new Type(TypeSet.EXTRA, "ACCESSORY", false, ModifierSource.ACCESSORY);
|
||||
public static final Type BLOCK = new Type(TypeSet.EXTRA, "BLOCK", false, ModifierSource.VOID);
|
||||
public static final Type ARMOR = new Type("ARMOR", false, ModifierSource.ARMOR);
|
||||
public static final Type TOOL = new Type("TOOL", false, ModifierSource.MELEE_WEAPON);
|
||||
public static final Type CONSUMABLE = new Type("CONSUMABLE", false, ModifierSource.MAINHAND_ITEM);
|
||||
public static final Type MISCELLANEOUS = new Type("MISCELLANEOUS", false, ModifierSource.MAINHAND_ITEM);
|
||||
public static final Type GEM_STONE = new Type("GEM_STONE", false, ModifierSource.VOID);
|
||||
public static final Type SKIN = new Type("SKIN", false, ModifierSource.VOID);
|
||||
public static final Type ACCESSORY = new Type("ACCESSORY", false, ModifierSource.ACCESSORY);
|
||||
public static final Type BLOCK = new Type("BLOCK", false, ModifierSource.VOID);
|
||||
|
||||
private final String id;
|
||||
private final TypeSet set;
|
||||
private final ModifierSource modifierSource;
|
||||
private final boolean weapon;
|
||||
|
||||
@ -69,6 +73,9 @@ public class Type {
|
||||
@Nullable
|
||||
private String loreFormat;
|
||||
|
||||
@NotNull
|
||||
private String attackCooldownKey;
|
||||
|
||||
/**
|
||||
* Used to display the item in the item explorer and in the item recipes
|
||||
* list in the advanced workbench. can also be edited using the config
|
||||
@ -77,58 +84,80 @@ public class Type {
|
||||
private ItemStack item;
|
||||
|
||||
/**
|
||||
* Any type can have a subtype which basically dictates what the item type
|
||||
* does.
|
||||
* The parent item type determines:
|
||||
* - the item options compatible with this new item type
|
||||
* - if this item type is a weapon or not
|
||||
* - types of modifiers an item of this type would give
|
||||
* - the lore format
|
||||
*/
|
||||
private Type parent;
|
||||
|
||||
private UnidentifiedItem unidentifiedTemplate;
|
||||
|
||||
private SkillHandler onLeftClick, onRightClick, onAttack, onEntityInteract;
|
||||
|
||||
public Script ent;
|
||||
|
||||
private boolean meleeAttacks;
|
||||
|
||||
/**
|
||||
* List of stats which can be applied onto an item which has this type. This
|
||||
* improves performance when generating an item by a significant amount.
|
||||
*/
|
||||
private final List<ItemStat> available = new ArrayList<>();
|
||||
|
||||
@Deprecated
|
||||
public Type(TypeSet set, String id, boolean weapon, ModifierSource modSource, boolean fourGUIMode) {
|
||||
this(set, id, weapon, modSource);
|
||||
}
|
||||
private final PostLoadAction postLoadAction = new PostLoadAction(true, config -> {
|
||||
onLeftClick = config.contains("on-left-click") ? MythicLib.plugin.getSkills().loadSkillHandler(config.get("on-left-click")) : null;
|
||||
onRightClick = config.contains("on-right-click") ? MythicLib.plugin.getSkills().loadSkillHandler(config.get("on-right-click")) : null;
|
||||
onAttack = config.contains("on-attack") ? MythicLib.plugin.getSkills().loadSkillHandler(config.get("on-attack")) : null;
|
||||
onEntityInteract = config.contains("on-entity-interact") ? MythicLib.plugin.getSkills().loadSkillHandler(config.get("on-entity-interact")) : null;
|
||||
});
|
||||
|
||||
public Type(TypeSet set, String id, boolean weapon, ModifierSource modSource) {
|
||||
this.set = set;
|
||||
this.id = id.toUpperCase().replace("-", "_").replace(" ", "_");
|
||||
/**
|
||||
* Hard-coded type with given parameters
|
||||
*/
|
||||
public Type(String id, boolean weapon, ModifierSource modSource) {
|
||||
this.id = UtilityMethods.enumName(id);
|
||||
this.modifierSource = modSource;
|
||||
this.weapon = weapon;
|
||||
this.loreFormat = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom type
|
||||
*/
|
||||
public Type(@NotNull TypeManager manager, @NotNull ConfigurationSection config) {
|
||||
id = config.getName().toUpperCase().replace("-", "_").replace(" ", "_");
|
||||
|
||||
id = UtilityMethods.enumName(config.getName());
|
||||
parent = manager.get(config.getString("parent", "").toUpperCase().replace("-", "_").replace(" ", "_"));
|
||||
|
||||
set = (parent != null ? parent.set : TypeSet.EXTRA);
|
||||
weapon = (parent != null && parent.weapon);
|
||||
modifierSource = (parent != null ? parent.modifierSource : ModifierSource.OTHER);
|
||||
this.loreFormat = config.getString("LoreFormat", (parent != null ? parent.loreFormat : null));
|
||||
weapon = config.getBoolean("weapon", parent != null && parent.weapon);
|
||||
modifierSource = config.contains("modifier-source") ? ModifierSource.valueOf(UtilityMethods.enumName(config.getString("modifier-source"))) : (parent != null ? parent.modifierSource : ModifierSource.OTHER);
|
||||
}
|
||||
|
||||
public void load(ConfigurationSection config) {
|
||||
Validate.notNull(config, "Could not find config for " + getId());
|
||||
public void load(@NotNull ConfigurationSection config) {
|
||||
postLoadAction.cacheConfig(config);
|
||||
|
||||
name = config.getString("name", name);
|
||||
item = read(config.getString("display", item == null ? Material.STONE.toString() : item.getType().toString()));
|
||||
|
||||
(unidentifiedTemplate = new UnidentifiedItem(this)).update(config.getConfigurationSection("unident-item"));
|
||||
loreFormat = config.getString("LoreFormat", (parent != null ? parent.loreFormat : null));
|
||||
attackCooldownKey = config.getString("attack-cooldown-key", "default");
|
||||
meleeAttacks = !config.getBoolean("disable-melee-attacks");
|
||||
}
|
||||
|
||||
// Getting overridden?
|
||||
loreFormat = config.getString("LoreFormat", (parent != null ? parent.loreFormat : loreFormat));
|
||||
@Deprecated
|
||||
public void postload(ConfigurationSection config) {
|
||||
postLoadAction.cacheConfig(config);
|
||||
postLoadAction.performAction();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public PostLoadAction getPostLoadAction() {
|
||||
return postLoadAction;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Type is no longer an enum so that external plugins
|
||||
* can register their own types. Use getId() instead
|
||||
* can register their own types. Use getId() instead
|
||||
*/
|
||||
@Deprecated
|
||||
public String name() {
|
||||
@ -144,18 +173,19 @@ public class Type {
|
||||
return id;
|
||||
}
|
||||
|
||||
public TypeSet getItemSet() {
|
||||
return set;
|
||||
}
|
||||
|
||||
public boolean isWeapon() {
|
||||
return weapon;
|
||||
}
|
||||
|
||||
public boolean hasMeleeAttacks() {
|
||||
return meleeAttacks;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public ModifierSource getModifierSource() {
|
||||
return modifierSource;
|
||||
}
|
||||
@ -164,6 +194,31 @@ public class Type {
|
||||
return item.clone();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public SkillHandler onLeftClick() {
|
||||
return onLeftClick;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCooldownPath() {
|
||||
return "mmoitems_weapons:" + attackCooldownKey;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public SkillHandler onRightClick() {
|
||||
return onRightClick;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public SkillHandler onAttack() {
|
||||
return onAttack;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public SkillHandler onEntityInteract() {
|
||||
return onEntityInteract;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link #getSupertype()}
|
||||
*/
|
||||
@ -207,21 +262,16 @@ public class Type {
|
||||
|
||||
/**
|
||||
* @return Either if the two types are the same,
|
||||
* or if this type is a subtype of the given type.
|
||||
* or if this type is a subtype of the given type.
|
||||
*/
|
||||
public boolean corresponds(Type type) {
|
||||
return getSupertype().equals(type);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public boolean corresponds(TypeSet set) {
|
||||
return getSupertype().getItemSet() == set;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The collection of all stats which can be applied onto this
|
||||
* specific item type. This list is cached when types are being
|
||||
* loaded and is a PRETTY GOOD performance improvement.
|
||||
* specific item type. This list is cached when types are being
|
||||
* loaded and is a PRETTY GOOD performance improvement.
|
||||
*/
|
||||
public List<ItemStat> getAvailableStats() {
|
||||
return available;
|
||||
@ -229,7 +279,7 @@ public class Type {
|
||||
|
||||
/**
|
||||
* @return Finds the /item config file corresponding to the item type and
|
||||
* loads it
|
||||
* loads it
|
||||
*/
|
||||
public ConfigFile getConfigFile() {
|
||||
return new ConfigFile("/item", getId().toLowerCase());
|
||||
@ -299,10 +349,12 @@ public class Type {
|
||||
*/
|
||||
@Nullable
|
||||
public static Type get(@Nullable String id) {
|
||||
if (id == null) return null;
|
||||
return id == null ? null : MMOItems.plugin.getTypes().get(UtilityMethods.enumName(id));
|
||||
}
|
||||
|
||||
String format = UtilityMethods.enumName(id);
|
||||
return MMOItems.plugin.getTypes().has(format) ? MMOItems.plugin.getTypes().get(format) : null;
|
||||
@Nullable
|
||||
public static Type get(@NotNull NBTItem item) {
|
||||
return get(item.getType());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,166 +0,0 @@
|
||||
package net.Indyuce.mmoitems.api;
|
||||
|
||||
import io.lumine.mythic.lib.UtilityMethods;
|
||||
import io.lumine.mythic.lib.comp.interaction.InteractionType;
|
||||
import io.lumine.mythic.lib.damage.AttackMetadata;
|
||||
import io.lumine.mythic.lib.damage.DamageType;
|
||||
import io.lumine.mythic.lib.player.PlayerMetadata;
|
||||
import io.lumine.mythic.lib.version.VersionSound;
|
||||
import net.Indyuce.mmoitems.MMOItems;
|
||||
import net.Indyuce.mmoitems.api.interaction.weapon.Weapon;
|
||||
import net.Indyuce.mmoitems.api.player.PlayerData;
|
||||
import net.Indyuce.mmoitems.api.player.PlayerData.CooldownType;
|
||||
import net.Indyuce.mmoitems.util.MMOUtils;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Particle;
|
||||
import org.bukkit.Sound;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.potion.PotionEffect;
|
||||
import org.bukkit.potion.PotionEffectType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
public enum TypeSet {
|
||||
|
||||
/**
|
||||
* Slashing weapons deal damage in a cone behind the player's initial
|
||||
* target, which makes it a deadly AoE weapon for warriors
|
||||
*/
|
||||
SLASHING((attack, attacker, attackerData, target, weapon) -> {
|
||||
if (!MMOItems.plugin.getConfig().getBoolean("item-ability.slashing.enabled")
|
||||
|| attackerData.isOnCooldown(CooldownType.SET_TYPE_ATTACK))
|
||||
return;
|
||||
|
||||
attackerData.applyCooldown(CooldownType.SET_TYPE_ATTACK, MMOItems.plugin.getConfig().getDouble("item-ability.slashing.cooldown"));
|
||||
Location loc = attacker.getPlayer().getLocation().clone().add(0, 1.3, 0);
|
||||
|
||||
final double a1 = (loc.getYaw() + 90) / 180 * Math.PI, p = -loc.getPitch() / 180 * Math.PI;
|
||||
for (double r = 1; r < 5; r += .3)
|
||||
for (double a = -Math.PI / 6; a < Math.PI / 6; a += Math.PI / 8 / r)
|
||||
loc.getWorld().spawnParticle(Particle.CRIT, loc.clone().add(Math.cos(a + a1) * r, Math.sin(p) * r, Math.sin(a + a1) * r), 0);
|
||||
|
||||
for (Entity entity : MMOUtils.getNearbyChunkEntities(loc))
|
||||
if (entity.getLocation().distanceSquared(loc) < 40
|
||||
&& attacker.getPlayer().getEyeLocation().getDirection()
|
||||
.angle(entity.getLocation().subtract(attacker.getPlayer().getLocation()).toVector()) < Math.PI / 3
|
||||
&& UtilityMethods.canTarget(attacker.getPlayer(), entity, InteractionType.OFFENSE_ACTION) && !entity.equals(target))
|
||||
attacker.attack((LivingEntity) entity, attack.getDamage().getDamage() * .4, DamageType.WEAPON, DamageType.PHYSICAL);
|
||||
}),
|
||||
|
||||
/**
|
||||
* Piercing weapons deal damage in a line behind the initial target, which
|
||||
* is harder to land than a slashing weapon but the AoE damage ratio is
|
||||
* increased which makes it a perfect 'double or nothing' weapon for
|
||||
* assassins
|
||||
*/
|
||||
PIERCING((attack, attacker, attackerData, target, weapon) -> {
|
||||
if (!MMOItems.plugin.getConfig().getBoolean("item-ability.piercing.enabled")
|
||||
|| attackerData.isOnCooldown(CooldownType.SET_TYPE_ATTACK))
|
||||
return;
|
||||
|
||||
attackerData.applyCooldown(CooldownType.SET_TYPE_ATTACK, MMOItems.plugin.getConfig().getDouble("item-ability.piercing.cooldown"));
|
||||
Location loc = attacker.getPlayer().getLocation().clone().add(0, 1.3, 0);
|
||||
|
||||
final double a1 = (loc.getYaw() + 90) / 180 * Math.PI, p = -loc.getPitch() / 180 * Math.PI;
|
||||
for (double r = 1; r < 5; r += .3)
|
||||
for (double a = -Math.PI / 12; a < Math.PI / 12; a += Math.PI / 16 / r)
|
||||
loc.getWorld().spawnParticle(Particle.CRIT, loc.clone().add(Math.cos(a + a1) * r, Math.sin(p) * r, Math.sin(a + a1) * r), 0);
|
||||
|
||||
for (Entity entity : MMOUtils.getNearbyChunkEntities(loc))
|
||||
if (!entity.equals(target) && entity.getLocation().distanceSquared(attacker.getPlayer().getLocation()) < 40
|
||||
&& attacker.getPlayer().getEyeLocation().getDirection()
|
||||
.angle(entity.getLocation().toVector().subtract(attacker.getPlayer().getLocation().toVector())) < Math.PI / 12
|
||||
&& UtilityMethods.canTarget(attacker.getPlayer(), entity, InteractionType.OFFENSE_ACTION))
|
||||
attacker.attack((LivingEntity) entity, attack.getDamage().getDamage() * .6, DamageType.WEAPON, DamageType.PHYSICAL);
|
||||
}),
|
||||
|
||||
/**
|
||||
* Blunt weapons are like 1.9 sweep attacks. They damage
|
||||
* all enemies nearby and apply a slight knockback
|
||||
*/
|
||||
BLUNT((attack, attacker, attackerData, target, weapon) -> {
|
||||
final Random random = new Random();
|
||||
float pitchRange = 0.7f + random.nextFloat() * (0.9f - 0.7f);
|
||||
|
||||
final double bluntPower;
|
||||
if (MMOItems.plugin.getConfig().getBoolean("item-ability.blunt.aoe.enabled")
|
||||
&& !attackerData.isOnCooldown(CooldownType.SPECIAL_ATTACK)
|
||||
&& (bluntPower = attacker.getStat("BLUNT_POWER")) > 0) {
|
||||
|
||||
attackerData.applyCooldown(CooldownType.SPECIAL_ATTACK, MMOItems.plugin.getConfig().getDouble("item-ability.blunt.aoe.cooldown"));
|
||||
target.getWorld().playSound(target.getLocation(), Sound.BLOCK_ANVIL_LAND, 0.6f, pitchRange);
|
||||
target.getWorld().spawnParticle(Particle.EXPLOSION_LARGE, target.getLocation().add(0, 1, 0), 0);
|
||||
final double bluntRating = weapon.requireNonZero(attacker.getStat("BLUNT_RATING"),
|
||||
MMOItems.plugin.getConfig().getDouble("default.blunt-rating")) / 100;
|
||||
for (Entity entity : target.getNearbyEntities(bluntPower, bluntPower, bluntPower))
|
||||
if (UtilityMethods.canTarget(attacker.getPlayer(), entity, InteractionType.OFFENSE_ACTION) && !entity.equals(target))
|
||||
attacker.attack((LivingEntity) entity, attack.getDamage().getDamage() * bluntRating, DamageType.WEAPON, DamageType.PHYSICAL);
|
||||
}
|
||||
|
||||
if (MMOItems.plugin.getConfig().getBoolean("item-ability.blunt.stun.enabled")
|
||||
&& !attackerData.isOnCooldown(CooldownType.SPECIAL_ATTACK)
|
||||
&& random.nextDouble() < MMOItems.plugin.getConfig().getDouble("item-ability.blunt.stun.chance") / 100) {
|
||||
|
||||
attackerData.applyCooldown(CooldownType.SPECIAL_ATTACK, MMOItems.plugin.getConfig().getDouble("item-ability.blunt.stun.cooldown"));
|
||||
target.getWorld().playSound(target.getLocation(), VersionSound.ENTITY_ZOMBIE_ATTACK_WOODEN_DOOR.toSound(), 1, 2);
|
||||
target.removePotionEffect(PotionEffectType.SLOW);
|
||||
target.removePotionEffect(PotionEffectType.BLINDNESS);
|
||||
target.addPotionEffect(new PotionEffect(PotionEffectType.BLINDNESS, 20, 0));
|
||||
target.addPotionEffect(
|
||||
new PotionEffect(PotionEffectType.SLOW, (int) (30 * MMOItems.plugin.getConfig().getDouble("item-ability.blunt.stun.power")), 1));
|
||||
Location loc = target.getLocation();
|
||||
loc.setYaw((float) (loc.getYaw() + 2 * (random.nextDouble() - .5) * 90));
|
||||
loc.setPitch((float) (loc.getPitch() + 2 * (random.nextDouble() - .5) * 30));
|
||||
}
|
||||
}),
|
||||
|
||||
/**
|
||||
* Ranged attacks based weapons. when the player is too squishy to fight in
|
||||
* the middle of the battle-field, these weapons allow him to take some
|
||||
* distance and still deal some good damage
|
||||
*/
|
||||
RANGE,
|
||||
|
||||
/**
|
||||
* Hand/Mainhand/Offhand catalysts
|
||||
*/
|
||||
CATALYST,
|
||||
|
||||
/**
|
||||
* Any other item type, like armor, consumables, etc. They all have their
|
||||
* very specific passive depending on their item type
|
||||
*/
|
||||
EXTRA;
|
||||
|
||||
private final SetAttackHandler attackHandler;
|
||||
private final String name;
|
||||
|
||||
private TypeSet() {
|
||||
this(null);
|
||||
}
|
||||
|
||||
private TypeSet(SetAttackHandler attackHandler) {
|
||||
this.attackHandler = attackHandler;
|
||||
|
||||
this.name = UtilityMethods.caseOnWords(name().toLowerCase());
|
||||
}
|
||||
|
||||
public boolean hasAttackEffect() {
|
||||
return attackHandler != null;
|
||||
}
|
||||
|
||||
public void applyAttackEffect(AttackMetadata attackMeta, PlayerMetadata attacker, PlayerData attackerData, LivingEntity target, Weapon weapon) {
|
||||
attackHandler.apply(attackMeta, attacker, attackerData, target, weapon);
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
interface SetAttackHandler {
|
||||
void apply(@NotNull AttackMetadata attack, @NotNull PlayerMetadata attacker, @NotNull PlayerData attackerData, @NotNull LivingEntity target, @NotNull Weapon weapon);
|
||||
}
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
package net.Indyuce.mmoitems.api.crafting;
|
||||
|
||||
import io.lumine.mythic.lib.api.util.PostLoadObject;
|
||||
import io.lumine.mythic.lib.util.PostLoadAction;
|
||||
import io.lumine.mythic.lib.util.PreloadedObject;
|
||||
import net.Indyuce.mmoitems.MMOItems;
|
||||
import net.Indyuce.mmoitems.api.crafting.ingredient.inventory.IngredientInventory;
|
||||
import net.Indyuce.mmoitems.api.crafting.recipe.CheckedRecipe;
|
||||
@ -13,12 +14,13 @@ import org.apache.commons.lang.Validate;
|
||||
import org.bukkit.Sound;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.configuration.file.FileConfiguration;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.logging.Level;
|
||||
|
||||
public class CraftingStation extends PostLoadObject {
|
||||
public class CraftingStation implements PreloadedObject {
|
||||
private final String id;
|
||||
private final String name;
|
||||
private final Layout layout;
|
||||
@ -38,8 +40,17 @@ public class CraftingStation extends PostLoadObject {
|
||||
|
||||
private CraftingStation parent;
|
||||
|
||||
private final PostLoadAction postLoadAction = new PostLoadAction(config -> {
|
||||
if (!config.contains("parent")) return;
|
||||
|
||||
String id = config.getString("parent").toLowerCase().replace(" ", "-").replace("_", "-");
|
||||
Validate.isTrue(!id.equals(CraftingStation.this.id), "Station cannot use itself as parent");
|
||||
Validate.isTrue(MMOItems.plugin.getCrafting().hasStation(id), "Could not find parent station with ID '" + id + "'");
|
||||
parent = MMOItems.plugin.getCrafting().getStation(id);
|
||||
});
|
||||
|
||||
public CraftingStation(String id, FileConfiguration config) {
|
||||
super(config);
|
||||
postLoadAction.cacheConfig(config);
|
||||
|
||||
this.id = id.toLowerCase().replace("_", "-").replace(" ", "-");
|
||||
this.name = config.getString("name", "Unnamed");
|
||||
@ -59,8 +70,6 @@ public class CraftingStation extends PostLoadObject {
|
||||
}
|
||||
|
||||
public CraftingStation(String id, String name, Layout layout, Sound sound, StationItemOptions itemOptions, int maxQueueSize, CraftingStation parent) {
|
||||
super(null);
|
||||
|
||||
Validate.notNull(id, "Crafting station ID must not be null");
|
||||
Validate.notNull(name, "Crafting station name must not be null");
|
||||
Validate.notNull(sound, "Crafting station sound must not be null");
|
||||
@ -74,6 +83,12 @@ public class CraftingStation extends PostLoadObject {
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public PostLoadAction getPostLoadAction() {
|
||||
return postLoadAction;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
@ -169,16 +184,6 @@ public class CraftingStation extends PostLoadObject {
|
||||
return Math.max(1, (int) Math.ceil((double) recipes / getLayout().getRecipeSlots().size()));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void whenPostLoaded(ConfigurationSection config) {
|
||||
if (config.contains("parent")) {
|
||||
String id = config.getString("parent").toLowerCase().replace(" ", "-").replace("_", "-");
|
||||
Validate.isTrue(!id.equals(this.id), "Station cannot use itself as parent");
|
||||
Validate.isTrue(MMOItems.plugin.getCrafting().hasStation(id), "Could not find parent station with ID '" + id + "'");
|
||||
parent = MMOItems.plugin.getCrafting().getStation(id);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* find type of crafting recipe based on section. there is no 'type' recipe
|
||||
* parameter because old files would be out of date, instead just looks for
|
||||
|
@ -1,14 +1,14 @@
|
||||
package net.Indyuce.mmoitems.api.event.item;
|
||||
|
||||
import net.Indyuce.mmoitems.api.event.PlayerDataEvent;
|
||||
import net.Indyuce.mmoitems.api.interaction.weapon.untargeted.UntargetedWeapon;
|
||||
import net.Indyuce.mmoitems.api.interaction.weapon.Weapon;
|
||||
import net.Indyuce.mmoitems.api.player.PlayerData;
|
||||
import org.bukkit.event.Cancellable;
|
||||
import org.bukkit.event.HandlerList;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class UntargetedWeaponUseEvent extends PlayerDataEvent implements Cancellable {
|
||||
private final UntargetedWeapon weapon;
|
||||
private final Weapon weapon;
|
||||
|
||||
private boolean cancelled;
|
||||
|
||||
@ -20,7 +20,7 @@ public class UntargetedWeaponUseEvent extends PlayerDataEvent implements Cancell
|
||||
* @param who Player attacking
|
||||
* @param weapon Weapon being used
|
||||
*/
|
||||
public UntargetedWeaponUseEvent(@NotNull PlayerData who, @NotNull UntargetedWeapon weapon) {
|
||||
public UntargetedWeaponUseEvent(@NotNull PlayerData who, @NotNull Weapon weapon) {
|
||||
super(who);
|
||||
|
||||
this.weapon = weapon;
|
||||
@ -30,7 +30,7 @@ public class UntargetedWeaponUseEvent extends PlayerDataEvent implements Cancell
|
||||
* @return The weapon used by the player that fired this event
|
||||
*/
|
||||
@NotNull
|
||||
public UntargetedWeapon getWeapon() {
|
||||
public Weapon getWeapon() {
|
||||
return weapon;
|
||||
}
|
||||
|
||||
|
@ -11,6 +11,7 @@ import net.Indyuce.mmoitems.api.Type;
|
||||
import net.Indyuce.mmoitems.api.event.item.ConsumableConsumedEvent;
|
||||
import net.Indyuce.mmoitems.api.item.mmoitem.VolatileMMOItem;
|
||||
import net.Indyuce.mmoitems.api.item.util.LoreUpdate;
|
||||
import net.Indyuce.mmoitems.api.player.PlayerData;
|
||||
import net.Indyuce.mmoitems.stat.type.ConsumableItemInteraction;
|
||||
import net.Indyuce.mmoitems.stat.type.PlayerConsumable;
|
||||
import org.bukkit.Bukkit;
|
||||
@ -22,10 +23,16 @@ import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class Consumable extends UseItem {
|
||||
|
||||
@Deprecated
|
||||
public Consumable(Player player, NBTItem item) {
|
||||
super(player, item);
|
||||
}
|
||||
|
||||
public Consumable(PlayerData player, NBTItem item) {
|
||||
super(player, item);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkItemRequirements() {
|
||||
return MythicLib.plugin.getFlags().isFlagAllowed(player, CustomFlag.MI_CONSUMABLES) && playerData.getRPG().canUse(getNBTItem(), true);
|
||||
|
@ -6,6 +6,7 @@ import net.Indyuce.mmoitems.api.Type;
|
||||
import net.Indyuce.mmoitems.api.event.item.ApplyGemStoneEvent;
|
||||
import net.Indyuce.mmoitems.api.item.mmoitem.LiveMMOItem;
|
||||
import net.Indyuce.mmoitems.api.item.mmoitem.MMOItem;
|
||||
import net.Indyuce.mmoitems.api.player.PlayerData;
|
||||
import net.Indyuce.mmoitems.api.util.message.Message;
|
||||
import net.Indyuce.mmoitems.stat.Enchants;
|
||||
import net.Indyuce.mmoitems.stat.GemUpgradeScaling;
|
||||
@ -28,11 +29,15 @@ import org.jetbrains.annotations.Nullable;
|
||||
import java.util.UUID;
|
||||
|
||||
public class GemStone extends UseItem {
|
||||
|
||||
@Deprecated
|
||||
public GemStone(Player player, NBTItem item) {
|
||||
super(player, item);
|
||||
}
|
||||
|
||||
public GemStone(PlayerData player, NBTItem item) {
|
||||
super(player, item);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public ApplyResult applyOntoItem(@NotNull NBTItem target, @NotNull Type targetType) {
|
||||
|
||||
@ -60,7 +65,7 @@ public class GemStone extends UseItem {
|
||||
// Checks if the gem supports the item type, or the item set, or a weapon
|
||||
String appliableTypes = getNBTItem().getString(ItemStats.ITEM_TYPE_RESTRICTION.getNBTPath());
|
||||
if (!appliableTypes.equals("") && (!targetType.isWeapon() || !appliableTypes.contains("WEAPON"))
|
||||
&& !appliableTypes.contains(targetType.getItemSet().name()) && !appliableTypes.contains(targetType.getId()))
|
||||
&& !appliableTypes.contains(targetType.getId()))
|
||||
return new ApplyResult(ResultType.NONE);
|
||||
|
||||
// Check for success rate
|
||||
|
@ -7,6 +7,7 @@ import net.Indyuce.mmoitems.ItemStats;
|
||||
import net.Indyuce.mmoitems.MMOItems;
|
||||
import net.Indyuce.mmoitems.api.Type;
|
||||
import net.Indyuce.mmoitems.api.item.mmoitem.VolatileMMOItem;
|
||||
import net.Indyuce.mmoitems.api.player.PlayerData;
|
||||
import net.Indyuce.mmoitems.api.util.message.Message;
|
||||
import net.Indyuce.mmoitems.stat.data.SkullTextureData;
|
||||
import net.Indyuce.mmoitems.stat.data.StringListData;
|
||||
@ -19,16 +20,20 @@ import org.bukkit.inventory.meta.Damageable;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
import org.bukkit.inventory.meta.LeatherArmorMeta;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.List;
|
||||
|
||||
public class ItemSkin extends UseItem {
|
||||
@Deprecated
|
||||
public ItemSkin(Player player, NBTItem item) {
|
||||
super(player, item);
|
||||
}
|
||||
|
||||
public ItemSkin(PlayerData player, NBTItem item) {
|
||||
super(player, item);
|
||||
}
|
||||
|
||||
public ApplyResult applyOntoItem(NBTItem target, Type targetType) {
|
||||
if (targetType == Type.SKIN)
|
||||
return new ApplyResult(ResultType.NONE);
|
||||
@ -42,9 +47,9 @@ public class ItemSkin extends UseItem {
|
||||
//SKIN//MMOItems.log("\u00a78SKIN \u00a7eCPT\u00a77 Applying onto " + MMOUtils.getDisplayName(target.getItem()));
|
||||
|
||||
// Types compatibility check
|
||||
if (getMMOItem().hasData(ItemStats.COMPATIBLE_TYPES)) {
|
||||
if (mmoitem.hasData(ItemStats.COMPATIBLE_TYPES)) {
|
||||
//SKIN//MMOItems.log("\u00a78SKIN \u00a7eCPT\u00a77 Testing that TYPE is compatible: ");
|
||||
final List<String> acceptedTypes = ((StringListData) getMMOItem().getData(ItemStats.COMPATIBLE_TYPES)).getList();
|
||||
final List<String> acceptedTypes = ((StringListData) mmoitem.getData(ItemStats.COMPATIBLE_TYPES)).getList();
|
||||
if (acceptedTypes.size() > 0 && acceptedTypes.stream().noneMatch(s -> s.equalsIgnoreCase(targetType.getId()))) {
|
||||
player.playSound(player.getLocation(), Sound.ENTITY_PLAYER_LEVELUP, 1, 2);
|
||||
Message.SKIN_INCOMPATIBLE.format(ChatColor.RED, "#item#", MMOUtils.getDisplayName(target.getItem()))
|
||||
@ -54,9 +59,9 @@ public class ItemSkin extends UseItem {
|
||||
}
|
||||
|
||||
// IDs compatibility check
|
||||
if (getMMOItem().hasData(ItemStats.COMPATIBLE_IDS)) {
|
||||
if (mmoitem.hasData(ItemStats.COMPATIBLE_IDS)) {
|
||||
//SKIN//MMOItems.log("\u00a78SKIN \u00a7eCPT\u00a77 Testing that ID is compatible: ");
|
||||
final List<String> acceptedIDs = ((StringListData) getMMOItem().getData(ItemStats.COMPATIBLE_IDS)).getList();
|
||||
final List<String> acceptedIDs = ((StringListData) mmoitem.getData(ItemStats.COMPATIBLE_IDS)).getList();
|
||||
final String targetId = target.getString("MMOITEMS_ITEM_ID");
|
||||
|
||||
if (acceptedIDs.size() > 0 && acceptedIDs.stream()
|
||||
@ -69,9 +74,9 @@ public class ItemSkin extends UseItem {
|
||||
}
|
||||
|
||||
// Material compatibility check
|
||||
if (getMMOItem().hasData(ItemStats.COMPATIBLE_MATERIALS)) {
|
||||
if (mmoitem.hasData(ItemStats.COMPATIBLE_MATERIALS)) {
|
||||
//SKIN//MMOItems.log("\u00a78SKIN \u00a7eCPT\u00a77 Testing that MATERIAL is compatible: ");
|
||||
List<String> acceptedMaterials = ((StringListData) getMMOItem().getData(ItemStats.COMPATIBLE_MATERIALS)).getList();
|
||||
List<String> acceptedMaterials = ((StringListData) mmoitem.getData(ItemStats.COMPATIBLE_MATERIALS)).getList();
|
||||
|
||||
if (acceptedMaterials.size() > 0 && acceptedMaterials.stream()
|
||||
.noneMatch(s -> s.equalsIgnoreCase(target.getItem().getType().name()))) {
|
||||
@ -93,7 +98,7 @@ public class ItemSkin extends UseItem {
|
||||
}
|
||||
|
||||
// Apply skin
|
||||
ItemStack item = applySkin(target, getMMOItem());
|
||||
ItemStack item = applySkin(target, mmoitem);
|
||||
|
||||
player.playSound(player.getLocation(), Sound.ENTITY_PLAYER_LEVELUP, 1, 2);
|
||||
Message.SKIN_APPLIED.format(ChatColor.YELLOW, "#item#", MMOUtils.getDisplayName(target.getItem())).send(player);
|
||||
|
@ -6,9 +6,9 @@ import io.lumine.mythic.lib.comp.flags.CustomFlag;
|
||||
import net.Indyuce.mmoitems.ItemStats;
|
||||
import net.Indyuce.mmoitems.MMOItems;
|
||||
import net.Indyuce.mmoitems.api.Type;
|
||||
import net.Indyuce.mmoitems.api.interaction.weapon.Gauntlet;
|
||||
import net.Indyuce.mmoitems.api.interaction.weapon.Weapon;
|
||||
import net.Indyuce.mmoitems.api.interaction.weapon.untargeted.*;
|
||||
import net.Indyuce.mmoitems.api.interaction.weapon.untargeted.Lute;
|
||||
import net.Indyuce.mmoitems.api.interaction.weapon.untargeted.Musket;
|
||||
import net.Indyuce.mmoitems.api.item.mmoitem.VolatileMMOItem;
|
||||
import net.Indyuce.mmoitems.api.player.PlayerData;
|
||||
import net.Indyuce.mmoitems.stat.data.CommandData;
|
||||
@ -27,11 +27,12 @@ public class UseItem {
|
||||
|
||||
protected static final Random RANDOM = new Random();
|
||||
|
||||
public UseItem(Player player, NBTItem nbtItem) {
|
||||
@Deprecated
|
||||
public UseItem(@NotNull Player player, @NotNull NBTItem nbtItem) {
|
||||
this(PlayerData.get(player), nbtItem);
|
||||
}
|
||||
|
||||
public UseItem(PlayerData playerData, NBTItem nbtItem) {
|
||||
public UseItem(@NotNull PlayerData playerData, @NotNull NBTItem nbtItem) {
|
||||
this.player = playerData.getPlayer();
|
||||
this.playerData = playerData;
|
||||
this.mmoitem = new VolatileMMOItem(nbtItem);
|
||||
@ -85,11 +86,9 @@ public class UseItem {
|
||||
private void scheduleCommandExecution(CommandData command) {
|
||||
String parsed = MythicLib.plugin.getPlaceholderParser().parse(player, command.getCommand());
|
||||
|
||||
if (!command.hasDelay())
|
||||
dispatchCommand(parsed, command.isConsoleCommand(), command.hasOpPerms());
|
||||
if (!command.hasDelay()) dispatchCommand(parsed, command.isConsoleCommand(), command.hasOpPerms());
|
||||
else
|
||||
Bukkit.getScheduler().runTaskLater(MMOItems.plugin, () -> dispatchCommand(parsed, command.isConsoleCommand(), command.hasOpPerms()),
|
||||
(long) command.getDelay() * 20);
|
||||
Bukkit.getScheduler().runTaskLater(MMOItems.plugin, () -> dispatchCommand(parsed, command.isConsoleCommand(), command.hasOpPerms()), (long) command.getDelay() * 20);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -116,33 +115,22 @@ public class UseItem {
|
||||
} finally {
|
||||
player.setOp(false);
|
||||
}
|
||||
} else
|
||||
Bukkit.dispatchCommand(player, parsed);
|
||||
} else Bukkit.dispatchCommand(player, parsed);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static UseItem getItem(Player player, NBTItem item, String type) {
|
||||
return getItem(player, item, Type.get(type));
|
||||
}
|
||||
|
||||
public static UseItem getItem(@NotNull Player player, @NotNull NBTItem item, @NotNull Type type) {
|
||||
if (type.corresponds(Type.CONSUMABLE))
|
||||
return new Consumable(player, item);
|
||||
if (type.corresponds(Type.SKIN))
|
||||
return new ItemSkin(player, item);
|
||||
if (type.corresponds(Type.GEM_STONE))
|
||||
return new GemStone(player, item);
|
||||
if (type.corresponds(Type.MUSKET))
|
||||
return new Musket(player, item);
|
||||
if (type.corresponds(Type.CROSSBOW))
|
||||
return new Crossbow(player, item);
|
||||
if (type.corresponds(Type.GAUNTLET))
|
||||
return new Gauntlet(player, item);
|
||||
if (type.corresponds(Type.WHIP))
|
||||
return new Whip(player, item);
|
||||
if (type.corresponds(Type.LUTE))
|
||||
return new Lute(player, item);
|
||||
if (type.corresponds(Type.STAFF))
|
||||
return new Staff(player, item);
|
||||
return type.isWeapon() ? new Weapon(player, item) : new UseItem(player, item);
|
||||
final PlayerData playerData = PlayerData.get(player);
|
||||
if (type.corresponds(Type.CONSUMABLE)) return new Consumable(playerData, item);
|
||||
if (type.corresponds(Type.SKIN)) return new ItemSkin(playerData, item);
|
||||
if (type.corresponds(Type.GEM_STONE)) return new GemStone(playerData, item);
|
||||
if (type.corresponds(Type.MUSKET)) return new Musket(playerData, item);
|
||||
if (type.corresponds(Type.LUTE)) return new Lute(playerData, item);
|
||||
|
||||
return type.isWeapon() ? new Weapon(playerData, item) : new UseItem(playerData, item);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,35 @@
|
||||
package net.Indyuce.mmoitems.api.interaction;
|
||||
|
||||
public enum WeaponAttackResult {
|
||||
|
||||
/**
|
||||
* Attack was performed successfully
|
||||
*/
|
||||
SUCCESS,
|
||||
|
||||
/**
|
||||
* Attakc was not performed due to missing resource (mana or stamina)
|
||||
* or ongoing cooldown.
|
||||
*/
|
||||
WEAPON_COSTS,
|
||||
|
||||
/**
|
||||
* Attack was canceled because the item is broken
|
||||
*/
|
||||
DURABILITY,
|
||||
|
||||
/**
|
||||
* Attack was canceled due to a precondition of the executed skill
|
||||
*/
|
||||
SKILL_SPECIFIC,
|
||||
|
||||
/**
|
||||
* Attack was canceled due to an event
|
||||
*/
|
||||
BUKKIT_EVENT,
|
||||
|
||||
/**
|
||||
* No attack effect was detected on the item.
|
||||
*/
|
||||
NO_ATTACK,
|
||||
}
|
@ -1,81 +0,0 @@
|
||||
package net.Indyuce.mmoitems.api.interaction.projectile;
|
||||
|
||||
import io.lumine.mythic.lib.MythicLib;
|
||||
import io.lumine.mythic.lib.api.item.NBTItem;
|
||||
import io.lumine.mythic.lib.player.PlayerMetadata;
|
||||
import net.Indyuce.mmoitems.stat.data.PotionEffectData;
|
||||
import org.apache.commons.lang.Validate;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.potion.PotionEffectType;
|
||||
|
||||
/**
|
||||
* Since MMOItems 6.7.5 vanilla bows and custom bows are
|
||||
* not treated the same way:
|
||||
* - vanilla bows see NO changes in their damage computations
|
||||
* - custom bows override
|
||||
*/
|
||||
public class ProjectileData {
|
||||
private final NBTItem sourceItem;
|
||||
private final PlayerMetadata shooter;
|
||||
private final double damageMultiplier;
|
||||
|
||||
@Deprecated
|
||||
public ProjectileData(PlayerMetadata shooter, NBTItem sourceItem, boolean customWeapon, double damageMultiplier) {
|
||||
this(shooter, sourceItem, damageMultiplier);
|
||||
}
|
||||
|
||||
public ProjectileData(PlayerMetadata shooter, NBTItem sourceItem, double damageMultiplier) {
|
||||
this.shooter = shooter;
|
||||
this.sourceItem = sourceItem;
|
||||
this.damageMultiplier = damageMultiplier;
|
||||
}
|
||||
|
||||
public NBTItem getSourceItem() {
|
||||
return sourceItem;
|
||||
}
|
||||
|
||||
public PlayerMetadata getShooter() {
|
||||
return shooter;
|
||||
}
|
||||
|
||||
public double getDamageMultiplier() {
|
||||
return damageMultiplier;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to check if that projectile data is linked to
|
||||
* a projectile that want sent using a MMOItems bow.
|
||||
* <p>
|
||||
* If so, it needs to apply on-hit effects like
|
||||
* elemental damage or on-hit potion effects
|
||||
*/
|
||||
@Deprecated
|
||||
public boolean isCustomWeapon() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Will throw an error if it's not a custom bow
|
||||
*
|
||||
* @return Damage of custom bow
|
||||
*/
|
||||
public double getDamage() {
|
||||
Validate.isTrue(isCustomWeapon(), "Not a custom bow");
|
||||
return shooter.getStat("ATTACK_DAMAGE") * damageMultiplier;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see {@link #getDamage()}
|
||||
*/
|
||||
@Deprecated
|
||||
public void setDamage(double damage) {
|
||||
Validate.isTrue(isCustomWeapon(), "Not a custom bow");
|
||||
shooter.setStat("ATTACK_DAMAGE", damage);
|
||||
}
|
||||
|
||||
public void applyPotionEffects(LivingEntity target) {
|
||||
if (sourceItem.hasTag("MMOITEMS_ARROW_POTION_EFFECTS"))
|
||||
for (ArrowPotionEffectArrayItem entry : MythicLib.plugin.getJson().parse(sourceItem.getString("MMOITEMS_ARROW_POTION_EFFECTS"), ArrowPotionEffectArrayItem[].class))
|
||||
target.addPotionEffect(new PotionEffectData(PotionEffectType.getByName(entry.type), entry.duration, entry.level).toEffect());
|
||||
}
|
||||
}
|
@ -1,33 +0,0 @@
|
||||
package net.Indyuce.mmoitems.api.interaction.weapon;
|
||||
|
||||
import io.lumine.mythic.lib.api.item.NBTItem;
|
||||
import net.Indyuce.mmoitems.MMOItems;
|
||||
import net.Indyuce.mmoitems.api.player.PlayerData.CooldownType;
|
||||
import org.bukkit.Particle;
|
||||
import org.bukkit.Sound;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.potion.PotionEffect;
|
||||
import org.bukkit.potion.PotionEffectType;
|
||||
|
||||
public class Gauntlet extends Weapon {
|
||||
public Gauntlet(Player player, NBTItem item) {
|
||||
super(player, item);
|
||||
}
|
||||
|
||||
public void specialAttack(LivingEntity target) {
|
||||
if (!MMOItems.plugin.getConfig().getBoolean("item-ability.gauntlet.enabled"))
|
||||
return;
|
||||
|
||||
if (!checkWeaponCosts(CooldownType.SPECIAL_ATTACK))
|
||||
return;
|
||||
|
||||
applyWeaponCosts(MMOItems.plugin.getConfig().getDouble("item-ability.gauntlet.cooldown"), CooldownType.SPECIAL_ATTACK);
|
||||
target.getWorld().spawnParticle(Particle.EXPLOSION_LARGE, target.getLocation().add(0, 1, 0), 0);
|
||||
target.getWorld().playSound(target.getLocation(), Sound.BLOCK_ANVIL_LAND, 1, 0);
|
||||
target.removePotionEffect(PotionEffectType.BLINDNESS);
|
||||
target.addPotionEffect(new PotionEffect(PotionEffectType.BLINDNESS, 40, 1));
|
||||
target.setVelocity(getPlayer().getEyeLocation().getDirection().setY(0).normalize().setY(.8));
|
||||
target.setVelocity(getPlayer().getEyeLocation().getDirection().setY(0).normalize().multiply(2).setY(.3));
|
||||
}
|
||||
}
|
@ -2,13 +2,28 @@ package net.Indyuce.mmoitems.api.interaction.weapon;
|
||||
|
||||
import io.lumine.mythic.lib.MythicLib;
|
||||
import io.lumine.mythic.lib.api.item.NBTItem;
|
||||
import io.lumine.mythic.lib.api.player.EquipmentSlot;
|
||||
import io.lumine.mythic.lib.comp.flags.CustomFlag;
|
||||
import io.lumine.mythic.lib.damage.AttackMetadata;
|
||||
import io.lumine.mythic.lib.player.PlayerMetadata;
|
||||
import io.lumine.mythic.lib.skill.SimpleSkill;
|
||||
import io.lumine.mythic.lib.skill.SkillMetadata;
|
||||
import io.lumine.mythic.lib.skill.handler.SkillHandler;
|
||||
import io.lumine.mythic.lib.skill.result.SkillResult;
|
||||
import io.lumine.mythic.lib.skill.trigger.TriggerMetadata;
|
||||
import io.lumine.mythic.lib.skill.trigger.TriggerType;
|
||||
import net.Indyuce.mmoitems.ItemStats;
|
||||
import net.Indyuce.mmoitems.MMOItems;
|
||||
import net.Indyuce.mmoitems.api.Type;
|
||||
import net.Indyuce.mmoitems.api.event.item.UntargetedWeaponUseEvent;
|
||||
import net.Indyuce.mmoitems.api.interaction.UseItem;
|
||||
import net.Indyuce.mmoitems.api.interaction.WeaponAttackResult;
|
||||
import net.Indyuce.mmoitems.api.interaction.util.UntargetedDurabilityItem;
|
||||
import net.Indyuce.mmoitems.api.interaction.weapon.untargeted.LegacyWeapon;
|
||||
import net.Indyuce.mmoitems.api.player.PlayerData;
|
||||
import net.Indyuce.mmoitems.api.player.PlayerData.CooldownType;
|
||||
import net.Indyuce.mmoitems.api.util.message.Message;
|
||||
import net.Indyuce.mmoitems.stat.ActionLeftClick;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
@ -18,6 +33,8 @@ import org.jetbrains.annotations.NotNull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class Weapon extends UseItem {
|
||||
|
||||
@Deprecated
|
||||
public Weapon(Player player, NBTItem item) {
|
||||
this(PlayerData.get(player), item);
|
||||
}
|
||||
@ -43,18 +60,17 @@ public class Weapon extends UseItem {
|
||||
* @return If the attack was cast successfully
|
||||
*/
|
||||
public boolean checkAndApplyWeaponCosts() {
|
||||
if (!checkWeaponCosts(null)) return false;
|
||||
applyWeaponCosts(0, null);
|
||||
if (!checkWeaponCosts(false)) return false;
|
||||
applyWeaponCosts(null);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks for cooldown, mana and stamina weapon costs
|
||||
*
|
||||
* @return If requirements were met ie the attack can be cast successfully
|
||||
* @return If instantaneous weapon costs are met.
|
||||
* @see {@link #applyWeaponCosts(Double)}
|
||||
*/
|
||||
public boolean checkWeaponCosts(@Nullable CooldownType cooldown) {
|
||||
if (cooldown != null && getPlayerData().isOnCooldown(cooldown))
|
||||
public boolean checkWeaponCosts(boolean cooldowns) {
|
||||
if (cooldowns && getPlayerData().getMMOPlayerData().getCooldownMap().isOnCooldown(mmoitem.getType()))
|
||||
return false;
|
||||
|
||||
double manaCost = getNBTItem().getStat("MANA_COST");
|
||||
@ -73,22 +89,25 @@ public class Weapon extends UseItem {
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies cooldown, mana and stamina weapon costs
|
||||
* Hard coded instantaneous weapon costs are as follows:
|
||||
* - mana and stamina (resources)
|
||||
* - cooldown (given by the item type attack cooldown key)
|
||||
* <p>
|
||||
* Other weapon costs are inherent to the item type and are
|
||||
* fully configurable inside of the types config file.
|
||||
*
|
||||
* @param attackDelay The weapon attack period/delay
|
||||
* @param cooldown The weapon cooldown type. When set to null, no
|
||||
* cooldown will be applied. This is made to handle
|
||||
* custom weapons
|
||||
* @see {@link #checkWeaponCosts(boolean)}
|
||||
*/
|
||||
public void applyWeaponCosts(double attackDelay, @Nullable CooldownType cooldown) {
|
||||
public void applyWeaponCosts(@Nullable Double attackDelay) {
|
||||
|
||||
double manaCost = getNBTItem().getStat("MANA_COST");
|
||||
final double manaCost = getNBTItem().getStat("MANA_COST");
|
||||
if (manaCost > 0) playerData.getRPG().giveMana(-manaCost);
|
||||
|
||||
double staminaCost = getNBTItem().getStat("STAMINA_COST");
|
||||
final double staminaCost = getNBTItem().getStat("STAMINA_COST");
|
||||
if (staminaCost > 0) playerData.getRPG().giveStamina(-staminaCost);
|
||||
|
||||
if (cooldown != null) getPlayerData().applyCooldown(cooldown, attackDelay);
|
||||
if (attackDelay != null)
|
||||
getPlayerData().getMMOPlayerData().getCooldownMap().applyCooldown(mmoitem.getType(), attackDelay);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -103,20 +122,120 @@ public class Weapon extends UseItem {
|
||||
public boolean handleTargetedAttack(AttackMetadata attackMeta, @NotNull PlayerMetadata attacker, LivingEntity target) {
|
||||
|
||||
// Handle weapon mana and stamina costs ONLY
|
||||
if (!checkAndApplyWeaponCosts())
|
||||
return false;
|
||||
if (!checkAndApplyWeaponCosts()) return false;
|
||||
|
||||
// Handle item set attack effects
|
||||
if (getMMOItem().getType().getItemSet().hasAttackEffect() && !getNBTItem().getBoolean("MMOITEMS_DISABLE_ATTACK_PASSIVE"))
|
||||
getMMOItem().getType().getItemSet().applyAttackEffect(attackMeta, attacker, playerData, target, this);
|
||||
// Handle on-hit attack effects
|
||||
final SkillHandler onHitSkill = mmoitem.getType().onAttack();
|
||||
if (onHitSkill != null && !getNBTItem().getBoolean("MMOITEMS_DISABLE_ATTACK_PASSIVE"))
|
||||
new SimpleSkill(onHitSkill).cast(new TriggerMetadata(attacker, TriggerType.API, target, attackMeta));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private SkillHandler findClickSkill(boolean rightClick) {
|
||||
String skillId = getNBTItem().getString((rightClick ? ItemStats.RIGHT_CLICK_SCRIPT : ItemStats.LEFT_CLICK_SCRIPT).getNBTPath());
|
||||
|
||||
// (Deprecated) Support for staff spirits on left-clicks
|
||||
if (!rightClick && (skillId == null || skillId.isEmpty()))
|
||||
skillId = getNBTItem().getString(ActionLeftClick.LEGACY_PATH);
|
||||
|
||||
if (skillId == null || skillId.isEmpty()) {
|
||||
|
||||
// Find item type action
|
||||
final Type itemType = mmoitem.getType();
|
||||
return rightClick ? itemType.onRightClick() : itemType.onLeftClick();
|
||||
}
|
||||
|
||||
// Override item type with custom action
|
||||
return MythicLib.plugin.getSkills().getHandler(skillId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the player interacts with the item. This method is used to
|
||||
* apply durability and cast the weapon attack
|
||||
*
|
||||
* @param rightClick Is the click a right click? If false, it's a left click.
|
||||
* @param actionHand Slot being interacted with
|
||||
* @return Null if there are no attack detected
|
||||
* @implNote Since MI 6.7.3 this method handles custom durability, cooldown
|
||||
* checks and player stat snapshots.
|
||||
*/
|
||||
@Nullable
|
||||
public WeaponAttackResult handleUntargetedAttack(boolean rightClick, @NotNull EquipmentSlot actionHand) {
|
||||
if (this instanceof LegacyWeapon) return legacyHandleUntargetedAttack(rightClick, actionHand);
|
||||
|
||||
// Check for item type attack effect
|
||||
final SkillHandler handler = findClickSkill(rightClick);
|
||||
if (handler == null) return WeaponAttackResult.NO_ATTACK;
|
||||
|
||||
// Check for attack effect conditions
|
||||
final SkillMetadata meta = new TriggerMetadata(getPlayerData().getMMOPlayerData(), TriggerType.API).toSkillMetadata(new SimpleSkill(handler));
|
||||
final SkillResult result = handler.getResult(meta);
|
||||
if (!result.isSuccessful(meta)) return WeaponAttackResult.NO_ATTACK;
|
||||
|
||||
// Check for durability
|
||||
UntargetedDurabilityItem durItem = new UntargetedDurabilityItem(getPlayer(), getNBTItem(), actionHand);
|
||||
if (durItem.isBroken()) return WeaponAttackResult.DURABILITY;
|
||||
|
||||
// Apply weapon instantaneous costs
|
||||
PlayerMetadata stats = getPlayerData().getStats().newTemporary(actionHand);
|
||||
if (!checkWeaponCosts(true)) return WeaponAttackResult.WEAPON_COSTS;
|
||||
|
||||
// Check for Bukkit event
|
||||
UntargetedWeaponUseEvent called = new UntargetedWeaponUseEvent(playerData, this);
|
||||
Bukkit.getPluginManager().callEvent(called);
|
||||
if (called.isCancelled()) return WeaponAttackResult.BUKKIT_EVENT;
|
||||
|
||||
// Attack is ready to be performed.
|
||||
// Apply weapon costs
|
||||
final double attackDelay = 1 / requireNonZero(stats.getStat("ATTACK_SPEED"), MMOItems.plugin.getConfig().getDouble("default.attack-speed"));
|
||||
applyWeaponCosts(attackDelay);
|
||||
|
||||
// Apply weapon attack effect
|
||||
handler.whenCast(result, meta);
|
||||
|
||||
// Apply durability loss
|
||||
if (durItem.isValid()) durItem.decreaseDurability(1).inventoryUpdate();
|
||||
return WeaponAttackResult.SUCCESS;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
private WeaponAttackResult legacyHandleUntargetedAttack(boolean rightClick, @NotNull EquipmentSlot actionHand) {
|
||||
|
||||
// Check for attack effect conditions
|
||||
if (((LegacyWeapon) this).canAttack(rightClick, actionHand)) return WeaponAttackResult.NO_ATTACK;
|
||||
|
||||
// Check for durability
|
||||
UntargetedDurabilityItem durItem = new UntargetedDurabilityItem(getPlayer(), getNBTItem(), actionHand);
|
||||
if (durItem.isBroken()) return WeaponAttackResult.DURABILITY;
|
||||
|
||||
// Apply weapon instantaneous costs
|
||||
PlayerMetadata stats = getPlayerData().getStats().newTemporary(actionHand);
|
||||
if (!checkWeaponCosts(true)) return WeaponAttackResult.WEAPON_COSTS;
|
||||
|
||||
// Check for Bukkit event
|
||||
UntargetedWeaponUseEvent called = new UntargetedWeaponUseEvent(playerData, this);
|
||||
Bukkit.getPluginManager().callEvent(called);
|
||||
if (called.isCancelled()) return WeaponAttackResult.BUKKIT_EVENT;
|
||||
|
||||
// Attack is ready to be performed.
|
||||
// Apply weapon costs
|
||||
final double attackDelay = 1 / requireNonZero(stats.getStat("ATTACK_SPEED"), MMOItems.plugin.getConfig().getDouble("default.attack-speed"));
|
||||
applyWeaponCosts(attackDelay);
|
||||
|
||||
// Apply weapon attack effect
|
||||
final PlayerMetadata caster = playerData.getMMOPlayerData().getStatMap().cache(actionHand);
|
||||
((LegacyWeapon) this).applyAttackEffect(caster, actionHand);
|
||||
|
||||
// Apply durability loss
|
||||
if (durItem.isValid()) durItem.decreaseDurability(1).inventoryUpdate();
|
||||
return WeaponAttackResult.SUCCESS;
|
||||
}
|
||||
|
||||
protected Location getGround(Location loc) {
|
||||
for (int j = 0; j < 20; j++) {
|
||||
if (loc.getBlock().getType().isSolid())
|
||||
return loc;
|
||||
if (loc.getBlock().getType().isSolid()) return loc;
|
||||
loc.add(0, -1, 0);
|
||||
}
|
||||
return loc;
|
||||
@ -125,7 +244,7 @@ public class Weapon extends UseItem {
|
||||
/**
|
||||
* @return First argument, or second if zero or lower
|
||||
*/
|
||||
public double requireNonZero(double number, double elseNumber) {
|
||||
protected double requireNonZero(double number, double elseNumber) {
|
||||
return number <= 0 ? elseNumber : number;
|
||||
}
|
||||
}
|
||||
|
@ -1,52 +0,0 @@
|
||||
package net.Indyuce.mmoitems.api.interaction.weapon.untargeted;
|
||||
|
||||
import io.lumine.mythic.lib.api.item.NBTItem;
|
||||
import io.lumine.mythic.lib.api.player.EquipmentSlot;
|
||||
import io.lumine.mythic.lib.player.PlayerMetadata;
|
||||
import io.lumine.mythic.lib.skill.trigger.TriggerType;
|
||||
import io.lumine.mythic.lib.util.CustomProjectile;
|
||||
import net.Indyuce.mmoitems.MMOItems;
|
||||
import net.Indyuce.mmoitems.api.CustomSound;
|
||||
import net.Indyuce.mmoitems.listener.CustomSoundListener;
|
||||
import org.bukkit.GameMode;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.Sound;
|
||||
import org.bukkit.entity.Arrow;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
public class Crossbow extends UntargetedWeapon {
|
||||
private boolean consumesArrow;
|
||||
|
||||
public Crossbow(Player player, NBTItem item) {
|
||||
super(player, item, UntargetedWeaponType.RIGHT_CLICK);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canAttack(EquipmentSlot slot) {
|
||||
consumesArrow = !getNBTItem().getBoolean("MMOITEMS_DISABLE_ARROW_CONSUMPTION");
|
||||
return player.getGameMode() == GameMode.CREATIVE || !consumesArrow || getPlayer().getInventory().containsAtLeast(new ItemStack(Material.ARROW), 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyAttackEffect(PlayerMetadata stats, EquipmentSlot slot) {
|
||||
|
||||
// Consume arrow
|
||||
if (getPlayer().getGameMode() != GameMode.CREATIVE && consumesArrow)
|
||||
getPlayer().getInventory().removeItem(new ItemStack(Material.ARROW));
|
||||
|
||||
final Arrow arrow = getPlayer().launchProjectile(Arrow.class);
|
||||
arrow.setVelocity(getPlayer().getEyeLocation().getDirection().multiply(3 * requireNonZero(stats.getStat("ARROW_VELOCITY"), 1)));
|
||||
getPlayer().setVelocity(getPlayer().getVelocity().setX(0).setZ(0));
|
||||
|
||||
// Play custom sound
|
||||
CustomSoundListener.playSound(getNBTItem().getItem(), CustomSound.ON_CROSSBOW, player, Sound.ENTITY_ARROW_SHOOT);
|
||||
|
||||
// Register custom projectile
|
||||
MMOItems.plugin.getEntities().registerCustomProjectile(getNBTItem(), stats, arrow, 1);
|
||||
|
||||
// Trigger abilities
|
||||
stats.getData().triggerSkills(TriggerType.SHOOT_BOW, slot, arrow);
|
||||
new CustomProjectile(stats.getData(), CustomProjectile.ProjectileType.ARROW, arrow, slot);
|
||||
}
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package net.Indyuce.mmoitems.api.interaction.weapon.untargeted;
|
||||
|
||||
import io.lumine.mythic.lib.api.player.EquipmentSlot;
|
||||
import io.lumine.mythic.lib.player.PlayerMetadata;
|
||||
|
||||
/**
|
||||
* These weapon types need to be adapted to raw YAML scripts.
|
||||
*/
|
||||
@Deprecated
|
||||
public interface LegacyWeapon {
|
||||
|
||||
@Deprecated
|
||||
boolean canAttack(boolean rightClick, EquipmentSlot slot);
|
||||
|
||||
@Deprecated
|
||||
void applyAttackEffect(PlayerMetadata stats, EquipmentSlot slot);
|
||||
}
|
@ -8,6 +8,8 @@ import io.lumine.mythic.lib.damage.DamageType;
|
||||
import io.lumine.mythic.lib.player.PlayerMetadata;
|
||||
import io.lumine.mythic.lib.version.VersionSound;
|
||||
import net.Indyuce.mmoitems.MMOItems;
|
||||
import net.Indyuce.mmoitems.api.interaction.weapon.Weapon;
|
||||
import net.Indyuce.mmoitems.api.player.PlayerData;
|
||||
import net.Indyuce.mmoitems.api.util.SoundReader;
|
||||
import net.Indyuce.mmoitems.stat.LuteAttackEffectStat.LuteAttackEffect;
|
||||
import net.Indyuce.mmoitems.stat.data.ProjectileParticlesData;
|
||||
@ -23,14 +25,20 @@ import org.jetbrains.annotations.NotNull;
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.List;
|
||||
|
||||
public class Lute extends UntargetedWeapon {
|
||||
@Deprecated
|
||||
public class Lute extends Weapon implements LegacyWeapon {
|
||||
@Deprecated
|
||||
public Lute(Player player, NBTItem item) {
|
||||
super(player, item, UntargetedWeaponType.RIGHT_CLICK);
|
||||
super(player, item);
|
||||
}
|
||||
|
||||
public Lute(PlayerData player, NBTItem item) {
|
||||
super(player, item);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canAttack(EquipmentSlot slot) {
|
||||
return true;
|
||||
public boolean canAttack(boolean rightClick, EquipmentSlot slot) {
|
||||
return rightClick;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -40,8 +48,7 @@ public class Lute extends UntargetedWeapon {
|
||||
final Vector weight = new Vector(0, -.003 * stats.getStat("NOTE_WEIGHT"), 0);
|
||||
|
||||
final @Nullable LuteAttackEffect effect = LuteAttackEffect.get(getNBTItem());
|
||||
@Deprecated
|
||||
final SoundReader sound = new SoundReader(getNBTItem().getString("MMOITEMS_LUTE_ATTACK_SOUND"), VersionSound.BLOCK_NOTE_BLOCK_BELL.toSound());
|
||||
@Deprecated final SoundReader sound = new SoundReader(getNBTItem().getString("MMOITEMS_LUTE_ATTACK_SOUND"), VersionSound.BLOCK_NOTE_BLOCK_BELL.toSound());
|
||||
final @NotNull ProjectileParticlesData projParticle = getNBTItem().hasTag("MMOITEMS_PROJECTILE_PARTICLES") ?
|
||||
new ProjectileParticlesData(getNBTItem().getString("MMOITEMS_PROJECTILE_PARTICLES")) : ProjectileParticlesData.DEFAULT;
|
||||
|
||||
|
@ -7,21 +7,28 @@ import io.lumine.mythic.lib.comp.interaction.InteractionType;
|
||||
import io.lumine.mythic.lib.damage.DamageType;
|
||||
import io.lumine.mythic.lib.player.PlayerMetadata;
|
||||
import io.lumine.mythic.lib.util.RayTrace;
|
||||
import net.Indyuce.mmoitems.ItemStats;
|
||||
import net.Indyuce.mmoitems.MMOItems;
|
||||
import net.Indyuce.mmoitems.api.interaction.weapon.Weapon;
|
||||
import net.Indyuce.mmoitems.api.player.PlayerData;
|
||||
import org.bukkit.Color;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Sound;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
public class Musket extends UntargetedWeapon {
|
||||
@Deprecated
|
||||
public class Musket extends Weapon implements LegacyWeapon {
|
||||
@Deprecated
|
||||
public Musket(Player player, NBTItem item) {
|
||||
super(player, item, UntargetedWeaponType.RIGHT_CLICK);
|
||||
super(player, item);
|
||||
}
|
||||
|
||||
public Musket(PlayerData player, NBTItem item) {
|
||||
super(player, item);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canAttack(EquipmentSlot slot) {
|
||||
return true;
|
||||
public boolean canAttack(boolean rightClick, EquipmentSlot slot) {
|
||||
return rightClick;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1,72 +0,0 @@
|
||||
package net.Indyuce.mmoitems.api.interaction.weapon.untargeted;
|
||||
|
||||
import io.lumine.mythic.lib.UtilityMethods;
|
||||
import io.lumine.mythic.lib.api.item.NBTItem;
|
||||
import io.lumine.mythic.lib.api.player.EquipmentSlot;
|
||||
import io.lumine.mythic.lib.comp.interaction.InteractionType;
|
||||
import io.lumine.mythic.lib.damage.DamageType;
|
||||
import io.lumine.mythic.lib.player.PlayerMetadata;
|
||||
import io.lumine.mythic.lib.util.RayTrace;
|
||||
import io.lumine.mythic.lib.version.VersionSound;
|
||||
import net.Indyuce.mmoitems.ItemStats;
|
||||
import net.Indyuce.mmoitems.MMOItems;
|
||||
import net.Indyuce.mmoitems.api.player.PlayerData.CooldownType;
|
||||
import net.Indyuce.mmoitems.stat.StaffSpiritStat.StaffSpirit;
|
||||
import org.bukkit.EntityEffect;
|
||||
import org.bukkit.Particle;
|
||||
import org.bukkit.Sound;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
public class Staff extends UntargetedWeapon {
|
||||
public Staff(Player player, NBTItem item) {
|
||||
super(player, item, UntargetedWeaponType.LEFT_CLICK);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canAttack(EquipmentSlot slot) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyAttackEffect(PlayerMetadata stats, EquipmentSlot slot) {
|
||||
|
||||
double attackDamage = requireNonZero(stats.getStat("ATTACK_DAMAGE"), 1);
|
||||
double range = requireNonZero(stats.getStat("RANGE"), MMOItems.plugin.getConfig().getDouble("default.range"));
|
||||
|
||||
StaffSpirit spirit = StaffSpirit.get(getNBTItem());
|
||||
if (spirit != null) {
|
||||
spirit.getAttack().handle(stats, attackDamage, getNBTItem(), slot, range);
|
||||
return;
|
||||
}
|
||||
|
||||
RayTrace trace = new RayTrace(stats.getPlayer(), slot, range, entity -> UtilityMethods.canTarget(stats.getPlayer(), entity, InteractionType.OFFENSE_ACTION));
|
||||
if (trace.hasHit())
|
||||
stats.attack(trace.getHit(), attackDamage, DamageType.WEAPON, DamageType.MAGIC, DamageType.PROJECTILE);
|
||||
trace.draw(.5, tick -> tick.getWorld().spawnParticle(Particle.EXPLOSION_NORMAL, tick, 0, .1, .1, .1, 0));
|
||||
getPlayer().getWorld().playSound(getPlayer().getLocation(), VersionSound.ENTITY_FIREWORK_ROCKET_TWINKLE.toSound(), 2, 2);
|
||||
|
||||
}
|
||||
|
||||
public void specialAttack(LivingEntity target) {
|
||||
if (!MMOItems.plugin.getConfig().getBoolean("item-ability.staff.enabled"))
|
||||
return;
|
||||
|
||||
if (!checkWeaponCosts(CooldownType.SPECIAL_ATTACK))
|
||||
return;
|
||||
|
||||
applyWeaponCosts(MMOItems.plugin.getConfig().getDouble("item-ability.staff.cooldown"), CooldownType.SPECIAL_ATTACK);
|
||||
double power = MMOItems.plugin.getConfig().getDouble("item-ability.staff.power");
|
||||
|
||||
try {
|
||||
Vector vec = target.getLocation().toVector().subtract(getPlayer().getLocation().toVector()).setY(0).normalize().multiply(1.75 * power).setY(.65 * power);
|
||||
target.getWorld().spawnParticle(Particle.EXPLOSION_LARGE, target.getLocation().add(0, 1, 0), 0);
|
||||
target.getWorld().spawnParticle(Particle.EXPLOSION_NORMAL, target.getLocation().add(0, 1, 0), 16, 0, 0, 0, .1);
|
||||
target.setVelocity(vec);
|
||||
target.playEffect(EntityEffect.HURT);
|
||||
target.getWorld().playSound(target.getLocation(), Sound.BLOCK_ANVIL_LAND, 1, 2);
|
||||
} catch (IllegalArgumentException ignored) {
|
||||
}
|
||||
}
|
||||
}
|
@ -1,78 +0,0 @@
|
||||
package net.Indyuce.mmoitems.api.interaction.weapon.untargeted;
|
||||
|
||||
import io.lumine.mythic.lib.api.item.NBTItem;
|
||||
import io.lumine.mythic.lib.api.player.EquipmentSlot;
|
||||
import io.lumine.mythic.lib.player.PlayerMetadata;
|
||||
import net.Indyuce.mmoitems.MMOItems;
|
||||
import net.Indyuce.mmoitems.api.event.item.UntargetedWeaponUseEvent;
|
||||
import net.Indyuce.mmoitems.api.interaction.util.UntargetedDurabilityItem;
|
||||
import net.Indyuce.mmoitems.api.interaction.weapon.Weapon;
|
||||
import net.Indyuce.mmoitems.api.player.PlayerData;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
public abstract class UntargetedWeapon extends Weapon {
|
||||
protected final UntargetedWeaponType weaponType;
|
||||
|
||||
public UntargetedWeapon(Player player, NBTItem item, UntargetedWeaponType weaponType) {
|
||||
super(player, item);
|
||||
|
||||
this.weaponType = weaponType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the player interacts with the item. This method is used to
|
||||
* apply durability and cast the weapon attack
|
||||
*
|
||||
* @param slot Slot being interacted with
|
||||
* @implNote Since MI 6.7.3 this method handles custom durability, cooldown
|
||||
* checks and player stat snapshots.
|
||||
*/
|
||||
public void handleTargetFreeAttack(EquipmentSlot slot) {
|
||||
if (!canAttack(slot))
|
||||
return;
|
||||
|
||||
// Check for durability
|
||||
UntargetedDurabilityItem durItem = new UntargetedDurabilityItem(getPlayer(), getNBTItem(), slot);
|
||||
if (durItem.isBroken())
|
||||
return;
|
||||
|
||||
// Apply weapon mana/stamina costs and cooldown
|
||||
PlayerMetadata stats = getPlayerData().getStats().newTemporary(slot);
|
||||
if (!checkWeaponCosts(PlayerData.CooldownType.BASIC_ATTACK))
|
||||
return;
|
||||
|
||||
// Check for Bukkit event
|
||||
UntargetedWeaponUseEvent called = new UntargetedWeaponUseEvent(playerData, this);
|
||||
Bukkit.getPluginManager().callEvent(called);
|
||||
if (called.isCancelled())
|
||||
return;
|
||||
|
||||
// Apply weapon costs
|
||||
double attackDelay = 1 / requireNonZero(stats.getStat("ATTACK_SPEED"), MMOItems.plugin.getConfig().getDouble("default.attack-speed"));
|
||||
applyWeaponCosts(attackDelay, PlayerData.CooldownType.BASIC_ATTACK);
|
||||
|
||||
// Specific weapon attack effect
|
||||
applyAttackEffect(stats, slot);
|
||||
|
||||
// Apply durability loss
|
||||
if (durItem.isValid())
|
||||
durItem.decreaseDurability(1).inventoryUpdate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Used for instance by the Crossbow item type to apply
|
||||
* ammo requirements. This is the first ever condition checked
|
||||
* when trying to perform an untargeted attack
|
||||
*
|
||||
* @param slot Slot used to attack
|
||||
* @return Extra attack condition, specific to the untargeted weapon type
|
||||
*/
|
||||
public abstract boolean canAttack(EquipmentSlot slot);
|
||||
|
||||
public abstract void applyAttackEffect(PlayerMetadata stats, EquipmentSlot slot);
|
||||
|
||||
public UntargetedWeaponType getWeaponType() {
|
||||
return weaponType;
|
||||
}
|
||||
}
|
@ -1,22 +0,0 @@
|
||||
package net.Indyuce.mmoitems.api.interaction.weapon.untargeted;
|
||||
|
||||
import org.bukkit.event.block.Action;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* Used to determine if the item must be left or right clicked in order to
|
||||
* cast a basic attack. Whips, staffs are left click weapons whereas muskets
|
||||
* are right click weapons
|
||||
*
|
||||
* @author cympe
|
||||
*/
|
||||
public enum UntargetedWeaponType {
|
||||
RIGHT_CLICK,
|
||||
LEFT_CLICK;
|
||||
|
||||
public boolean corresponds(@NotNull Action action) {
|
||||
return this == RIGHT_CLICK ?
|
||||
action == Action.RIGHT_CLICK_AIR || action == Action.RIGHT_CLICK_BLOCK :
|
||||
action == Action.LEFT_CLICK_AIR || action == Action.LEFT_CLICK_BLOCK;
|
||||
}
|
||||
}
|
@ -1,38 +0,0 @@
|
||||
package net.Indyuce.mmoitems.api.interaction.weapon.untargeted;
|
||||
|
||||
import io.lumine.mythic.lib.UtilityMethods;
|
||||
import io.lumine.mythic.lib.api.item.NBTItem;
|
||||
import io.lumine.mythic.lib.api.player.EquipmentSlot;
|
||||
import io.lumine.mythic.lib.comp.interaction.InteractionType;
|
||||
import io.lumine.mythic.lib.damage.DamageType;
|
||||
import io.lumine.mythic.lib.player.PlayerMetadata;
|
||||
import io.lumine.mythic.lib.util.RayTrace;
|
||||
import io.lumine.mythic.lib.version.VersionSound;
|
||||
import net.Indyuce.mmoitems.ItemStats;
|
||||
import net.Indyuce.mmoitems.MMOItems;
|
||||
import org.bukkit.Particle;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
public class Whip extends UntargetedWeapon {
|
||||
public Whip(Player player, NBTItem item) {
|
||||
super(player, item, UntargetedWeaponType.LEFT_CLICK);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canAttack(EquipmentSlot slot) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyAttackEffect(PlayerMetadata stats, EquipmentSlot slot) {
|
||||
|
||||
double attackDamage = requireNonZero(stats.getStat("ATTACK_DAMAGE"), 7);
|
||||
double range = requireNonZero(getNBTItem().getStat(ItemStats.RANGE.getId()), MMOItems.plugin.getConfig().getDouble("default.range"));
|
||||
|
||||
RayTrace trace = new RayTrace(getPlayer(), slot, range, entity -> UtilityMethods.canTarget(stats.getPlayer(), entity, InteractionType.OFFENSE_ACTION));
|
||||
if (trace.hasHit())
|
||||
stats.attack(trace.getHit(), attackDamage, DamageType.WEAPON, DamageType.PROJECTILE, DamageType.PHYSICAL);
|
||||
trace.draw(.5, 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);
|
||||
}
|
||||
}
|
@ -18,6 +18,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Deprecated
|
||||
public class BruteLuteAttack implements LuteAttackHandler {
|
||||
|
||||
@Override
|
||||
|
@ -18,6 +18,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Deprecated
|
||||
public class CircularLuteAttack implements LuteAttackHandler {
|
||||
|
||||
@Override
|
||||
|
@ -9,6 +9,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
@Deprecated
|
||||
public interface LuteAttackHandler {
|
||||
static final Random RANDOM = new Random();
|
||||
|
||||
|
@ -18,6 +18,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Deprecated
|
||||
public class SimpleLuteAttack implements LuteAttackHandler {
|
||||
|
||||
@Override
|
||||
|
@ -16,6 +16,7 @@ import org.bukkit.scheduler.BukkitRunnable;
|
||||
import org.bukkit.util.Vector;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@Deprecated
|
||||
public class SlashLuteAttack implements LuteAttackHandler {
|
||||
|
||||
@Override
|
||||
|
@ -18,6 +18,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Deprecated
|
||||
public class WaveLuteAttack implements LuteAttackHandler {
|
||||
|
||||
@Override
|
||||
|
@ -1,25 +0,0 @@
|
||||
package net.Indyuce.mmoitems.api.interaction.weapon.untargeted.staff;
|
||||
|
||||
import io.lumine.mythic.lib.UtilityMethods;
|
||||
import io.lumine.mythic.lib.api.item.NBTItem;
|
||||
import io.lumine.mythic.lib.api.player.EquipmentSlot;
|
||||
import io.lumine.mythic.lib.comp.interaction.InteractionType;
|
||||
import io.lumine.mythic.lib.damage.DamageType;
|
||||
import io.lumine.mythic.lib.player.PlayerMetadata;
|
||||
import io.lumine.mythic.lib.util.RayTrace;
|
||||
import io.lumine.mythic.lib.version.VersionSound;
|
||||
import org.bukkit.Particle;
|
||||
|
||||
public class LightningSpirit implements StaffAttackHandler {
|
||||
|
||||
@Override
|
||||
public void handle(PlayerMetadata caster, double damage, NBTItem nbt, EquipmentSlot slot, double range) {
|
||||
caster.getPlayer().getWorld().playSound(caster.getPlayer().getLocation(), VersionSound.ENTITY_FIREWORK_ROCKET_BLAST.toSound(), 2, 2);
|
||||
|
||||
RayTrace trace = new RayTrace(caster.getPlayer(), slot, range, entity -> UtilityMethods.canTarget(caster.getPlayer(), entity, InteractionType.OFFENSE_ACTION));
|
||||
|
||||
if (trace.hasHit())
|
||||
caster.attack(trace.getHit(), damage, DamageType.WEAPON, DamageType.MAGIC, DamageType.PROJECTILE);
|
||||
trace.draw(.5, loc1 -> loc1.getWorld().spawnParticle(Particle.FIREWORKS_SPARK, loc1, 0));
|
||||
}
|
||||
}
|
@ -1,62 +0,0 @@
|
||||
package net.Indyuce.mmoitems.api.interaction.weapon.untargeted.staff;
|
||||
|
||||
import io.lumine.mythic.lib.UtilityMethods;
|
||||
import io.lumine.mythic.lib.api.item.NBTItem;
|
||||
import io.lumine.mythic.lib.api.player.EquipmentSlot;
|
||||
import io.lumine.mythic.lib.comp.interaction.InteractionType;
|
||||
import io.lumine.mythic.lib.damage.DamageType;
|
||||
import io.lumine.mythic.lib.player.PlayerMetadata;
|
||||
import net.Indyuce.mmoitems.MMOItems;
|
||||
import net.Indyuce.mmoitems.util.MMOUtils;
|
||||
import org.bukkit.Color;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Particle;
|
||||
import org.bukkit.Sound;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.scheduler.BukkitRunnable;
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class ManaSpirit implements StaffAttackHandler {
|
||||
|
||||
@Override
|
||||
public void handle(PlayerMetadata caster, double damage, NBTItem nbt, EquipmentSlot slot, double range) {
|
||||
new BukkitRunnable() {
|
||||
final Vector vec = caster.getPlayer().getEyeLocation().getDirection().multiply(.4);
|
||||
final Location loc = caster.getPlayer().getEyeLocation();
|
||||
int ti = 0;
|
||||
final double r = .2;
|
||||
|
||||
public void run() {
|
||||
if (ti++ > range)
|
||||
cancel();
|
||||
|
||||
if (ti % 2 == 0)
|
||||
loc.getWorld().playSound(loc, Sound.BLOCK_SNOW_BREAK, 2, 2);
|
||||
List<Entity> targets = MMOUtils.getNearbyChunkEntities(loc);
|
||||
for (int j = 0; j < 3; j++) {
|
||||
loc.add(vec);
|
||||
if (loc.getBlock().getType().isSolid()) {
|
||||
cancel();
|
||||
break;
|
||||
}
|
||||
|
||||
for (double item = 0; item < Math.PI * 2; item += Math.PI / 3.5) {
|
||||
Vector vec = MMOUtils.rotateFunc(new Vector(r * Math.cos(item), r * Math.sin(item), 0), loc);
|
||||
if (RANDOM.nextDouble() <= .6)
|
||||
loc.getWorld().spawnParticle(Particle.REDSTONE, loc.clone().add(vec), 1, new Particle.DustOptions(Color.AQUA, 1));
|
||||
}
|
||||
for (Entity target : targets)
|
||||
if (UtilityMethods.canTarget(caster.getPlayer(), loc, target, InteractionType.OFFENSE_ACTION)) {
|
||||
caster.attack((LivingEntity) target, damage, DamageType.WEAPON, DamageType.MAGIC, DamageType.PROJECTILE);
|
||||
loc.getWorld().spawnParticle(Particle.EXPLOSION_LARGE, loc, 0);
|
||||
cancel();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}.runTaskTimer(MMOItems.plugin, 0, 1);
|
||||
}
|
||||
}
|
@ -1,56 +0,0 @@
|
||||
package net.Indyuce.mmoitems.api.interaction.weapon.untargeted.staff;
|
||||
|
||||
import io.lumine.mythic.lib.UtilityMethods;
|
||||
import io.lumine.mythic.lib.api.item.NBTItem;
|
||||
import io.lumine.mythic.lib.api.player.EquipmentSlot;
|
||||
import io.lumine.mythic.lib.comp.interaction.InteractionType;
|
||||
import io.lumine.mythic.lib.damage.DamageType;
|
||||
import io.lumine.mythic.lib.player.PlayerMetadata;
|
||||
import net.Indyuce.mmoitems.MMOItems;
|
||||
import net.Indyuce.mmoitems.util.MMOUtils;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Particle;
|
||||
import org.bukkit.Sound;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.scheduler.BukkitRunnable;
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class NetherSpirit implements StaffAttackHandler {
|
||||
|
||||
@Override
|
||||
public void handle(PlayerMetadata caster, double damage, NBTItem nbt, EquipmentSlot slot, double range) {
|
||||
new BukkitRunnable() {
|
||||
final Vector vec = caster.getPlayer().getEyeLocation().getDirection().multiply(.3);
|
||||
final Location loc = caster.getPlayer().getEyeLocation();
|
||||
int ti = 0;
|
||||
|
||||
public void run() {
|
||||
if (ti++ % 2 == 0)
|
||||
loc.getWorld().playSound(loc, Sound.BLOCK_FIRE_AMBIENT, 2, 2);
|
||||
List<Entity> targets = MMOUtils.getNearbyChunkEntities(loc);
|
||||
for (int j = 0; j < 3; j++) {
|
||||
loc.add(vec);
|
||||
if (loc.getBlock().getType().isSolid()) {
|
||||
cancel();
|
||||
break;
|
||||
}
|
||||
|
||||
loc.getWorld().spawnParticle(Particle.FLAME, loc, 2, .07, .07, .07, 0);
|
||||
loc.getWorld().spawnParticle(Particle.SMOKE_NORMAL, loc, 0);
|
||||
for (Entity target : targets)
|
||||
if (UtilityMethods.canTarget(caster.getPlayer(), loc, target, InteractionType.OFFENSE_ACTION)) {
|
||||
caster.attack((LivingEntity) target, damage, DamageType.WEAPON, DamageType.MAGIC, DamageType.PROJECTILE);
|
||||
loc.getWorld().spawnParticle(Particle.EXPLOSION_LARGE, loc, 0);
|
||||
cancel();
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (ti >= range)
|
||||
cancel();
|
||||
}
|
||||
}.runTaskTimer(MMOItems.plugin, 0, 1);
|
||||
}
|
||||
}
|
@ -1,23 +0,0 @@
|
||||
package net.Indyuce.mmoitems.api.interaction.weapon.untargeted.staff;
|
||||
|
||||
import io.lumine.mythic.lib.api.item.NBTItem;
|
||||
import io.lumine.mythic.lib.api.player.EquipmentSlot;
|
||||
import io.lumine.mythic.lib.player.PlayerMetadata;
|
||||
import org.bukkit.Location;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
public interface StaffAttackHandler {
|
||||
static final Random RANDOM = new Random();
|
||||
|
||||
void handle(PlayerMetadata caster, double damage, NBTItem nbt, EquipmentSlot slot, double range);
|
||||
|
||||
default Location getGround(Location loc) {
|
||||
for (int j = 0; j < 20; j++) {
|
||||
if (loc.getBlock().getType().isSolid())
|
||||
return loc;
|
||||
loc.add(0, -1, 0);
|
||||
}
|
||||
return loc;
|
||||
}
|
||||
}
|
@ -1,59 +0,0 @@
|
||||
package net.Indyuce.mmoitems.api.interaction.weapon.untargeted.staff;
|
||||
|
||||
import io.lumine.mythic.lib.UtilityMethods;
|
||||
import io.lumine.mythic.lib.api.item.NBTItem;
|
||||
import io.lumine.mythic.lib.api.player.EquipmentSlot;
|
||||
import io.lumine.mythic.lib.comp.interaction.InteractionType;
|
||||
import io.lumine.mythic.lib.damage.DamageType;
|
||||
import io.lumine.mythic.lib.player.PlayerMetadata;
|
||||
import io.lumine.mythic.lib.version.VersionSound;
|
||||
import net.Indyuce.mmoitems.MMOItems;
|
||||
import net.Indyuce.mmoitems.util.MMOUtils;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Particle;
|
||||
import org.bukkit.Sound;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.scheduler.BukkitRunnable;
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
public class SunfireSpirit implements StaffAttackHandler {
|
||||
|
||||
@Override
|
||||
public void handle(PlayerMetadata caster, double damage, NBTItem nbt, EquipmentSlot slot, double range) {
|
||||
caster.getPlayer().getWorld().playSound(caster.getPlayer().getLocation(), Sound.ENTITY_WITHER_SHOOT, 2, 2);
|
||||
new BukkitRunnable() {
|
||||
final Location target = getGround(caster.getPlayer().getTargetBlock(null, (int) range * 2).getLocation()).add(0, 1.2, 0);
|
||||
final double a = RANDOM.nextDouble() * Math.PI * 2;
|
||||
final double dt = .02;
|
||||
final Location loc = target.clone().add(Math.cos(a) * 4, 10, Math.sin(a) * 4);
|
||||
final Vector vec = target.toVector().subtract(loc.toVector()).multiply(dt);
|
||||
double ti = 0;
|
||||
int counter;
|
||||
|
||||
public void run() {
|
||||
if (counter++ % 2 == 0)
|
||||
loc.getWorld().playSound(loc, Sound.BLOCK_FIRE_AMBIENT, 2, 2);
|
||||
|
||||
for (int j = 0; j < 3; j++) {
|
||||
ti += dt;
|
||||
loc.add(vec);
|
||||
loc.getWorld().spawnParticle(Particle.FLAME, loc, 0, .03, 0, .03, 0);
|
||||
|
||||
// Projectile explode
|
||||
if (ti >= 1) {
|
||||
loc.getWorld().spawnParticle(Particle.FLAME, loc, 24, 0, 0, 0, .12);
|
||||
loc.getWorld().spawnParticle(Particle.SMOKE_NORMAL, loc, 24, 0, 0, 0, .12);
|
||||
loc.getWorld().spawnParticle(Particle.EXPLOSION_LARGE, loc, 0);
|
||||
loc.getWorld().playSound(loc, VersionSound.ENTITY_FIREWORK_ROCKET_BLAST.toSound(), 2, 2);
|
||||
for (Entity target : MMOUtils.getNearbyChunkEntities(loc))
|
||||
if (UtilityMethods.canTarget(caster.getPlayer(), target, InteractionType.OFFENSE_ACTION) && target.getLocation().distanceSquared(loc) <= 9)
|
||||
caster.attack((LivingEntity) target, damage, DamageType.WEAPON, DamageType.MAGIC, DamageType.PROJECTILE);
|
||||
cancel();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}.runTaskTimer(MMOItems.plugin, 0, 1);
|
||||
}
|
||||
}
|
@ -1,57 +0,0 @@
|
||||
package net.Indyuce.mmoitems.api.interaction.weapon.untargeted.staff;
|
||||
|
||||
import io.lumine.mythic.lib.UtilityMethods;
|
||||
import io.lumine.mythic.lib.api.item.NBTItem;
|
||||
import io.lumine.mythic.lib.api.player.EquipmentSlot;
|
||||
import io.lumine.mythic.lib.comp.interaction.InteractionType;
|
||||
import io.lumine.mythic.lib.damage.DamageType;
|
||||
import io.lumine.mythic.lib.player.PlayerMetadata;
|
||||
import io.lumine.mythic.lib.version.VersionSound;
|
||||
import net.Indyuce.mmoitems.MMOItems;
|
||||
import net.Indyuce.mmoitems.util.MMOUtils;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Particle;
|
||||
import org.bukkit.Sound;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.scheduler.BukkitRunnable;
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
public class ThunderSpirit implements StaffAttackHandler {
|
||||
|
||||
@Override
|
||||
public void handle(PlayerMetadata caster, double damage, NBTItem nbt, EquipmentSlot slot, double range) {
|
||||
caster.getPlayer().getWorld().playSound(caster.getPlayer().getLocation(), Sound.ENTITY_WITHER_SHOOT, 2, 2);
|
||||
new BukkitRunnable() {
|
||||
final Location target = getGround(caster.getPlayer().getTargetBlock(null, (int) range * 2).getLocation()).add(0, 1.2, 0);
|
||||
final double a = RANDOM.nextDouble() * Math.PI * 2;
|
||||
final double dt = .02;
|
||||
double ti = 0;
|
||||
final Location loc = target.clone().add(Math.cos(a) * 4, 10, Math.sin(a) * 4);
|
||||
final Vector vec = target.toVector().subtract(loc.toVector()).multiply(dt);
|
||||
int counter;
|
||||
|
||||
public void run() {
|
||||
if (counter++ % 2 == 0)
|
||||
loc.getWorld().playSound(loc, VersionSound.BLOCK_NOTE_BLOCK_HAT.toSound(), 2, 2);
|
||||
|
||||
for (int j = 0; j < 3; j++) {
|
||||
ti += dt;
|
||||
loc.add(vec);
|
||||
loc.getWorld().spawnParticle(Particle.FIREWORKS_SPARK, loc, 0, .03, 0, .03, 0);
|
||||
|
||||
// Projectile explode
|
||||
if (ti >= 1) {
|
||||
loc.getWorld().spawnParticle(Particle.FIREWORKS_SPARK, loc, 24, 0, 0, 0, .12);
|
||||
loc.getWorld().playSound(loc, VersionSound.ENTITY_FIREWORK_ROCKET_BLAST.toSound(), 2, 2);
|
||||
for (Entity target : MMOUtils.getNearbyChunkEntities(loc))
|
||||
if (UtilityMethods.canTarget(caster.getPlayer(), target, InteractionType.OFFENSE_ACTION) && target.getLocation().distanceSquared(loc) <= 9)
|
||||
caster.attack((LivingEntity) target, damage, DamageType.WEAPON, DamageType.MAGIC, DamageType.PROJECTILE);
|
||||
cancel();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}.runTaskTimer(MMOItems.plugin, 0, 1);
|
||||
}
|
||||
}
|
@ -1,38 +0,0 @@
|
||||
package net.Indyuce.mmoitems.api.interaction.weapon.untargeted.staff;
|
||||
|
||||
import io.lumine.mythic.lib.api.item.NBTItem;
|
||||
import io.lumine.mythic.lib.api.player.EquipmentSlot;
|
||||
import io.lumine.mythic.lib.damage.DamageMetadata;
|
||||
import io.lumine.mythic.lib.damage.DamageType;
|
||||
import io.lumine.mythic.lib.player.PlayerMetadata;
|
||||
import net.Indyuce.mmoitems.MMOItems;
|
||||
import net.Indyuce.mmoitems.skill.ShulkerMissile;
|
||||
import org.bukkit.Sound;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.entity.ShulkerBullet;
|
||||
import org.bukkit.scheduler.BukkitRunnable;
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
public class VoidSpirit implements StaffAttackHandler {
|
||||
|
||||
@Override
|
||||
public void handle(PlayerMetadata caster, double damage, NBTItem nbt, EquipmentSlot slot, double range) {
|
||||
Vector vec = caster.getPlayer().getEyeLocation().getDirection();
|
||||
caster.getPlayer().getWorld().playSound(caster.getPlayer().getLocation(), Sound.ENTITY_WITHER_SHOOT, 2, 2);
|
||||
ShulkerBullet shulkerBullet = (ShulkerBullet) caster.getPlayer().getWorld().spawnEntity(caster.getPlayer().getLocation().add(0, 1, 0), EntityType.valueOf("SHULKER_BULLET"));
|
||||
shulkerBullet.setShooter(caster.getPlayer());
|
||||
new BukkitRunnable() {
|
||||
double ti = 0;
|
||||
|
||||
public void run() {
|
||||
ti += .1;
|
||||
if (shulkerBullet.isDead() || ti >= range / 4) {
|
||||
shulkerBullet.remove();
|
||||
cancel();
|
||||
}
|
||||
shulkerBullet.setVelocity(vec);
|
||||
}
|
||||
}.runTaskTimer(MMOItems.plugin, 0, 1);
|
||||
MMOItems.plugin.getEntities().registerCustomEntity(shulkerBullet, new ShulkerMissile.ShulkerMissileEntityData(caster, new DamageMetadata(damage, DamageType.WEAPON, DamageType.MAGIC, DamageType.PROJECTILE), 0, nbt));
|
||||
}
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
package net.Indyuce.mmoitems.api.interaction.weapon.untargeted.staff;
|
||||
|
||||
import io.lumine.mythic.lib.UtilityMethods;
|
||||
import io.lumine.mythic.lib.api.item.NBTItem;
|
||||
import io.lumine.mythic.lib.api.player.EquipmentSlot;
|
||||
import io.lumine.mythic.lib.comp.interaction.InteractionType;
|
||||
import io.lumine.mythic.lib.damage.DamageType;
|
||||
import io.lumine.mythic.lib.player.PlayerMetadata;
|
||||
import io.lumine.mythic.lib.util.RayTrace;
|
||||
import org.bukkit.Color;
|
||||
import org.bukkit.Sound;
|
||||
|
||||
public class XRaySpirit implements StaffAttackHandler {
|
||||
|
||||
@Override
|
||||
public void handle(PlayerMetadata caster, double damage, NBTItem nbt, EquipmentSlot slot, double range) {
|
||||
caster.getPlayer().getWorld().playSound(caster.getPlayer().getLocation(), Sound.BLOCK_FIRE_EXTINGUISH, 2, 2);
|
||||
|
||||
RayTrace trace = new RayTrace(caster.getPlayer(), slot, range, entity -> UtilityMethods.canTarget(caster.getPlayer(), entity, InteractionType.OFFENSE_ACTION));
|
||||
if (trace.hasHit())
|
||||
caster.attack(trace.getHit(), damage, DamageType.WEAPON, DamageType.MAGIC, DamageType.PROJECTILE);
|
||||
trace.draw(.5, Color.BLACK);
|
||||
caster.getPlayer().getWorld().playSound(caster.getPlayer().getLocation(), Sound.ENTITY_ZOMBIE_ATTACK_IRON_DOOR, 0.40f, 2);
|
||||
}
|
||||
}
|
@ -1,8 +1,10 @@
|
||||
package net.Indyuce.mmoitems.api.item.template;
|
||||
|
||||
import io.lumine.mythic.lib.api.util.PostLoadObject;
|
||||
import io.lumine.mythic.lib.UtilityMethods;
|
||||
import io.lumine.mythic.lib.api.util.ui.FriendlyFeedbackCategory;
|
||||
import io.lumine.mythic.lib.api.util.ui.FriendlyFeedbackProvider;
|
||||
import io.lumine.mythic.lib.util.PostLoadAction;
|
||||
import io.lumine.mythic.lib.util.PreloadedObject;
|
||||
import net.Indyuce.mmoitems.MMOItems;
|
||||
import net.Indyuce.mmoitems.api.ItemTier;
|
||||
import net.Indyuce.mmoitems.api.Type;
|
||||
@ -25,7 +27,7 @@ import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public class MMOItemTemplate extends PostLoadObject implements ItemReference {
|
||||
public class MMOItemTemplate implements ItemReference, PreloadedObject {
|
||||
private final Type type;
|
||||
private final String id;
|
||||
private final int revId;
|
||||
@ -42,40 +44,7 @@ public class MMOItemTemplate extends PostLoadObject implements ItemReference {
|
||||
private ModifierGroup modifierGroup;
|
||||
private final Set<TemplateOption> options = new HashSet<>();
|
||||
|
||||
/**
|
||||
* Public constructor which can be used to register extra item templates
|
||||
* using other addons or plugins
|
||||
*
|
||||
* @param type The item type of your template
|
||||
* @param id The template identifier, it's ok if two templates with
|
||||
* different item types share the same ID
|
||||
*/
|
||||
public MMOItemTemplate(Type type, String id) {
|
||||
super(null);
|
||||
|
||||
this.type = type;
|
||||
this.id = id;
|
||||
this.revId = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to load MMOItem templates from config files
|
||||
*
|
||||
* @param type The item type of your template
|
||||
* @param config The config file read to load the template
|
||||
*/
|
||||
public MMOItemTemplate(Type type, ConfigurationSection config) {
|
||||
super(config);
|
||||
Validate.notNull(config, "Could not load template config");
|
||||
|
||||
this.type = type;
|
||||
this.id = config.getName().toUpperCase().replace("-", "_").replace(" ", "_");
|
||||
this.revId = config.getInt("base.revision-id", 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void whenPostLoaded(ConfigurationSection config) {
|
||||
|
||||
private final PostLoadAction postLoadAction = new PostLoadAction(config -> {
|
||||
FriendlyFeedbackProvider ffp = new FriendlyFeedbackProvider(FFPMMOItems.get());
|
||||
ffp.activatePrefix(true, getType().getId() + " " + getId());
|
||||
|
||||
@ -95,7 +64,7 @@ public class MMOItemTemplate extends PostLoadObject implements ItemReference {
|
||||
|
||||
// Read modifiers
|
||||
try {
|
||||
modifierGroup = config.contains("modifiers") ? new ModifierGroup(id, config) : null;
|
||||
modifierGroup = config.contains("modifiers") ? new ModifierGroup(getId(), config) : null;
|
||||
if (modifierGroup != null) modifierGroup.getPostLoadAction().performAction();
|
||||
} catch (Exception exception) {
|
||||
ffp.log(FriendlyFeedbackCategory.ERROR, "Could not load modifier group: {0}", exception.getMessage());
|
||||
@ -105,10 +74,9 @@ public class MMOItemTemplate extends PostLoadObject implements ItemReference {
|
||||
Validate.notNull(config.getConfigurationSection("base"), FriendlyFeedbackProvider.quickForConsole(FFPMMOItems.get(), "Could not find base item data"));
|
||||
for (String key : config.getConfigurationSection("base").getKeys(false))
|
||||
try {
|
||||
String id = key.toUpperCase().replace("-", "_");
|
||||
Validate.isTrue(MMOItems.plugin.getStats().has(id), FriendlyFeedbackProvider.quickForConsole(FFPMMOItems.get(), "Could not find stat with ID '$i{0}$b'", id));
|
||||
|
||||
ItemStat stat = MMOItems.plugin.getStats().get(id);
|
||||
final String id = UtilityMethods.enumName(key);
|
||||
final ItemStat stat = MMOItems.plugin.getStats().get(id);
|
||||
Validate.notNull(stat, FriendlyFeedbackProvider.quickForConsole(FFPMMOItems.get(), "Could not find stat with ID '$i{0}$b'", id));
|
||||
RandomStatData data = stat.whenInitialized(config.get("base." + key));
|
||||
if (data != null)
|
||||
base.put(stat, data);
|
||||
@ -121,6 +89,42 @@ public class MMOItemTemplate extends PostLoadObject implements ItemReference {
|
||||
|
||||
// Print all failures
|
||||
ffp.sendTo(FriendlyFeedbackCategory.INFORMATION, MMOItems.getConsole());
|
||||
});
|
||||
|
||||
/**
|
||||
* Public constructor which can be used to register extra item templates
|
||||
* using other addons or plugins
|
||||
*
|
||||
* @param type The item type of your template
|
||||
* @param id The template identifier, it's ok if two templates with
|
||||
* different item types share the same ID
|
||||
*/
|
||||
public MMOItemTemplate(Type type, String id) {
|
||||
this.type = type;
|
||||
this.id = id;
|
||||
this.revId = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to load MMOItem templates from config files
|
||||
*
|
||||
* @param type The item type of your template
|
||||
* @param config The config file read to load the template
|
||||
*/
|
||||
public MMOItemTemplate(Type type, ConfigurationSection config) {
|
||||
Validate.notNull(config, "Could not load template config");
|
||||
|
||||
postLoadAction.cacheConfig(config);
|
||||
|
||||
this.type = type;
|
||||
this.id = config.getName().toUpperCase().replace("-", "_").replace(" ", "_");
|
||||
this.revId = config.getInt("base.revision-id", 1);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public PostLoadAction getPostLoadAction() {
|
||||
return postLoadAction;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@ -281,8 +285,8 @@ public class MMOItemTemplate extends PostLoadObject implements ItemReference {
|
||||
|
||||
/**
|
||||
* @return Attempts to get the crafted amount registered in the Stat.
|
||||
* <p></p>
|
||||
* Default is <b>1</b> obviously.
|
||||
* <p></p>
|
||||
* Default is <b>1</b> obviously.
|
||||
* @deprecated Don't use this method, the Crafted Amount Stat will be deleted in the near future.
|
||||
*/
|
||||
@Deprecated
|
||||
|
@ -1,7 +1,7 @@
|
||||
package net.Indyuce.mmoitems.api.item.template;
|
||||
|
||||
import io.lumine.mythic.lib.UtilityMethods;
|
||||
import io.lumine.mythic.lib.util.PostLoadAction;
|
||||
import io.lumine.mythic.lib.util.PreloadedObject;
|
||||
import net.Indyuce.mmoitems.MMOItems;
|
||||
import net.Indyuce.mmoitems.api.item.build.MMOItemBuilder;
|
||||
import net.Indyuce.mmoitems.stat.data.random.RandomStatData;
|
||||
@ -22,10 +22,9 @@ public class TemplateModifier extends ModifierNode {
|
||||
Validate.notNull(config.getConfigurationSection("stats"), "Could not find base item data");
|
||||
for (String key : config.getConfigurationSection("stats").getKeys(false))
|
||||
try {
|
||||
String id = key.toUpperCase().replace("-", "_");
|
||||
Validate.isTrue(MMOItems.plugin.getStats().has(id), "Could not find stat with ID '" + id + "'");
|
||||
|
||||
ItemStat stat = MMOItems.plugin.getStats().get(id);
|
||||
final String statId = UtilityMethods.enumName(key);
|
||||
final ItemStat stat = MMOItems.plugin.getStats().get(statId);
|
||||
Validate.notNull(stat, "Could not find stat with ID '" + statId + "'");
|
||||
TemplateModifier.this.data.put(stat, stat.whenInitialized(config.get("stats." + key)));
|
||||
} catch (IllegalArgumentException exception) {
|
||||
MMOItems.plugin.getLogger().log(Level.INFO, "An error occurred while trying to load modifier node " + getId() + ": " + exception.getMessage());
|
||||
|
@ -408,11 +408,6 @@ public class PlayerData extends SynchronizedDataHolder implements Closeable {
|
||||
|
||||
public enum CooldownType {
|
||||
|
||||
/**
|
||||
* Basic attack cooldown like staffs and lutes
|
||||
*/
|
||||
BASIC_ATTACK,
|
||||
|
||||
/**
|
||||
* Elemental attacks cooldown
|
||||
*/
|
||||
@ -431,12 +426,6 @@ public class PlayerData extends SynchronizedDataHolder implements Closeable {
|
||||
*
|
||||
* @see {@link Tool#miningEffects(Block)}
|
||||
*/
|
||||
BOUNCING_CRACK,
|
||||
|
||||
/**
|
||||
* Special item set attack effects including slashing, piercing and
|
||||
* blunt attack effects
|
||||
*/
|
||||
SET_TYPE_ATTACK
|
||||
BOUNCING_CRACK;
|
||||
}
|
||||
}
|
||||
|
@ -59,7 +59,7 @@ public class ReloadCommandTreeNode extends CommandTreeNode {
|
||||
|
||||
MMOItems.plugin.getLanguage().reload();
|
||||
MMOItems.plugin.getDropTables().reload();
|
||||
MMOItems.plugin.getTypes().reload();
|
||||
MMOItems.plugin.getTypes().reload(true);
|
||||
MMOItems.plugin.getTiers().reload();
|
||||
MMOItems.plugin.getSets().reload();
|
||||
MMOItems.plugin.getUpgrades().reload();
|
||||
|
@ -12,7 +12,6 @@ public class ListCommandTreeNode extends CommandTreeNode {
|
||||
|
||||
addChild(new AbilityCommandTreeNode(this));
|
||||
addChild(new LuteAttackCommandTreeNode(this));
|
||||
addChild(new StaffSpiritCommandTreeNode(this));
|
||||
addChild(new TypeCommandTreeNode(this));
|
||||
}
|
||||
|
||||
@ -21,7 +20,6 @@ public class ListCommandTreeNode extends CommandTreeNode {
|
||||
sender.sendMessage(ChatColor.DARK_GRAY + "" + ChatColor.STRIKETHROUGH + "-----------------[" + ChatColor.LIGHT_PURPLE + " MMOItems: lists "
|
||||
+ ChatColor.DARK_GRAY + "" + ChatColor.STRIKETHROUGH + "]-----------------");
|
||||
sender.sendMessage(ChatColor.LIGHT_PURPLE + "/mi list type " + ChatColor.WHITE + "shows all item types (sword, axe...)");
|
||||
sender.sendMessage(ChatColor.LIGHT_PURPLE + "/mi list spirit " + ChatColor.WHITE + "shows all available staff spirits");
|
||||
sender.sendMessage(ChatColor.LIGHT_PURPLE + "/mi list lute " + ChatColor.WHITE + "shows all available lute attack effects");
|
||||
sender.sendMessage(ChatColor.LIGHT_PURPLE + "/mi list ability " + ChatColor.WHITE + "shows all available abilities");
|
||||
if (sender instanceof Player) {
|
||||
|
@ -1,24 +0,0 @@
|
||||
package net.Indyuce.mmoitems.command.mmoitems.list;
|
||||
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
|
||||
import net.Indyuce.mmoitems.stat.StaffSpiritStat.StaffSpirit;
|
||||
import io.lumine.mythic.lib.command.api.CommandTreeNode;
|
||||
|
||||
public class StaffSpiritCommandTreeNode extends CommandTreeNode {
|
||||
public StaffSpiritCommandTreeNode(CommandTreeNode parent) {
|
||||
super(parent, "spirit");
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandResult execute(CommandSender sender, String[] args) {
|
||||
sender.sendMessage(ChatColor.DARK_GRAY + "" + ChatColor.STRIKETHROUGH + "-----------------[" + ChatColor.LIGHT_PURPLE + " Staff Spirits "
|
||||
+ ChatColor.DARK_GRAY + "" + ChatColor.STRIKETHROUGH + "]-----------------");
|
||||
for (StaffSpirit ss : StaffSpirit.values()) {
|
||||
String lore = ss.hasLore() ? " " + ChatColor.WHITE + ">> " + ChatColor.GRAY + "" + ChatColor.ITALIC + ss.getDefaultLore() : "";
|
||||
sender.sendMessage("* " + ChatColor.LIGHT_PURPLE + ss.name() + lore);
|
||||
}
|
||||
return CommandResult.SUCCESS;
|
||||
}
|
||||
}
|
@ -7,7 +7,7 @@ import io.lumine.mythic.bukkit.events.MythicReloadedEvent;
|
||||
import net.Indyuce.mmoitems.MMOItems;
|
||||
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.mechanics.MMOItemsOnUseAura;
|
||||
import net.Indyuce.mmoitems.comp.mythicmobs.stat.FactionDamage;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
@ -34,17 +34,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().getManager(), event.getContainer().getFile(), event.getContainer().getConfigLine(), event.getConfig()));
|
||||
event.register(new MMOItemsArrowVolleyMechanic(event.getContainer().getManager(),
|
||||
event.getContainer().getFile(),
|
||||
event.getConfig().getLine(),
|
||||
event.getConfig()));
|
||||
break;
|
||||
case "onmmoitemuse":
|
||||
event.register(new MMOItemsOnShootAura(event.getContainer().getManager(), event.getContainer().getFile(), event.getContainer().getConfigLine(), event.getConfig()));
|
||||
event.register(new MMOItemsOnUseAura(event.getContainer().getManager(),
|
||||
event.getContainer().getFile(),
|
||||
event.getConfig().getLine(),
|
||||
event.getConfig()));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
@ -12,7 +12,6 @@ import io.lumine.mythic.core.skills.auras.Aura;
|
||||
import io.lumine.mythic.bukkit.utils.Events;
|
||||
import net.Indyuce.mmoitems.MMOItems;
|
||||
import net.Indyuce.mmoitems.api.event.item.SpecialWeaponAttackEvent;
|
||||
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;
|
||||
@ -31,7 +30,7 @@ import java.util.Optional;
|
||||
*
|
||||
* @author Gunging
|
||||
*/
|
||||
public class MMOItemsOnShootAura extends Aura implements ITargetedEntitySkill {
|
||||
public class MMOItemsOnUseAura extends Aura implements ITargetedEntitySkill {
|
||||
@NotNull
|
||||
PlaceholderString skillName;
|
||||
@NotNull
|
||||
@ -44,7 +43,7 @@ public class MMOItemsOnShootAura extends Aura implements ITargetedEntitySkill {
|
||||
@NotNull
|
||||
final ArrayList<UseItemTypes> auraWeapons = new ArrayList<>();
|
||||
|
||||
public MMOItemsOnShootAura(SkillExecutor manager, File file, String line, MythicLineConfig mlc) {
|
||||
public MMOItemsOnUseAura(SkillExecutor manager, File file, String line, MythicLineConfig mlc) {
|
||||
super(manager, file, line, mlc);
|
||||
|
||||
skillName = mlc.getPlaceholderString(new String[]{"skill", "s", "ondamagedskill", "ondamaged", "od", "onhitskill", "onhit", "oh", "meta", "m", "mechanics", "$", "()"}, "skill not found");
|
||||
@ -109,7 +108,7 @@ public class MMOItemsOnShootAura extends Aura implements ITargetedEntitySkill {
|
||||
caster = new GenericCaster(target);
|
||||
}
|
||||
|
||||
new MMOItemsOnShootAura.Tracker(caster, data, target);
|
||||
new MMOItemsOnUseAura.Tracker(caster, data, target);
|
||||
return SkillResult.SUCCESS;
|
||||
}
|
||||
|
||||
@ -169,7 +168,7 @@ public class MMOItemsOnShootAura extends Aura implements ITargetedEntitySkill {
|
||||
}
|
||||
|
||||
}));
|
||||
this.executeAuraSkill(MMOItemsOnShootAura.this.onStartSkill, this.skillMetadata);
|
||||
this.executeAuraSkill(MMOItemsOnUseAura.this.onStartSkill, this.skillMetadata);
|
||||
}
|
||||
}
|
||||
|
||||
@ -223,12 +222,13 @@ public class MMOItemsOnShootAura extends Aura implements ITargetedEntitySkill {
|
||||
}
|
||||
|
||||
enum UseItemTypes {
|
||||
CROSSBOW(Crossbow.class),
|
||||
GAUNTLET(Gauntlet.class),
|
||||
// CROSSBOW(Crossbow.class),
|
||||
// GAUNTLET(Gauntlet.class),
|
||||
LUTE(Lute.class),
|
||||
MUSKET(Musket.class),
|
||||
STAFF(Staff.class),
|
||||
WHIP(Whip.class);
|
||||
// STAFF(Staff.class),
|
||||
// WHIP(Whip.class);
|
||||
;
|
||||
|
||||
/**
|
||||
* @return Class to use InstanceOf and identify a weapon.
|
@ -13,7 +13,6 @@ import org.bukkit.ChatColor;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.inventory.InventoryClickEvent;
|
||||
import org.bukkit.inventory.Inventory;
|
||||
import org.bukkit.inventory.ItemFlag;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
@ -21,6 +20,7 @@ import org.bukkit.inventory.meta.ItemMeta;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class ItemEdition extends EditionInventory {
|
||||
private static final int[] slots = {19, 20, 21, 22, 23, 24, 25, 28, 29, 30, 31, 32, 33, 34, 37, 38, 39, 40, 41, 42, 43};
|
||||
@ -45,7 +45,7 @@ public class ItemEdition extends EditionInventory {
|
||||
* the for loop will just let some slots empty
|
||||
*/
|
||||
List<ItemStat> appliable = new ArrayList<>(getEdited().getType().getAvailableStats()).stream()
|
||||
.filter(stat -> stat.hasValidMaterial(getCachedItem()) && !(stat instanceof InternalStat)).toList();
|
||||
.filter(stat -> stat.hasValidMaterial(getCachedItem()) && !(stat instanceof InternalStat)).collect(Collectors.toList());
|
||||
|
||||
for (int j = min; j < Math.min(appliable.size(), max); j++) {
|
||||
ItemStat stat = appliable.get(j);
|
||||
@ -53,7 +53,7 @@ public class ItemEdition extends EditionInventory {
|
||||
ItemMeta meta = item.getItemMeta();
|
||||
meta.addItemFlags(ItemFlag.values());
|
||||
meta.setDisplayName(ChatColor.GREEN + stat.getName());
|
||||
List<String> lore = MythicLib.plugin.parseColors(Arrays.stream(stat.getLore()).map(s -> ChatColor.GRAY + s).toList());
|
||||
List<String> lore = MythicLib.plugin.parseColors(Arrays.stream(stat.getLore()).map(s -> ChatColor.GRAY + s).collect(Collectors.toList()));
|
||||
lore.add("");
|
||||
|
||||
stat.whenDisplayed(lore, getEventualStatData(stat));
|
||||
|
@ -13,7 +13,6 @@ import org.bukkit.Material;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.inventory.InventoryAction;
|
||||
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;
|
||||
|
@ -7,16 +7,17 @@ import io.lumine.mythic.lib.api.item.NBTItem;
|
||||
import io.lumine.mythic.lib.api.player.EquipmentSlot;
|
||||
import io.lumine.mythic.lib.comp.interaction.InteractionType;
|
||||
import io.lumine.mythic.lib.damage.MeleeAttackMetadata;
|
||||
import net.Indyuce.mmoitems.MMOItems;
|
||||
import io.lumine.mythic.lib.entity.ProjectileMetadata;
|
||||
import io.lumine.mythic.lib.entity.ProjectileType;
|
||||
import io.lumine.mythic.lib.skill.SimpleSkill;
|
||||
import io.lumine.mythic.lib.skill.handler.SkillHandler;
|
||||
import io.lumine.mythic.lib.skill.trigger.TriggerMetadata;
|
||||
import io.lumine.mythic.lib.skill.trigger.TriggerType;
|
||||
import net.Indyuce.mmoitems.api.Type;
|
||||
import net.Indyuce.mmoitems.api.TypeSet;
|
||||
import net.Indyuce.mmoitems.api.event.item.SpecialWeaponAttackEvent;
|
||||
import net.Indyuce.mmoitems.api.interaction.*;
|
||||
import net.Indyuce.mmoitems.api.interaction.projectile.ProjectileData;
|
||||
import net.Indyuce.mmoitems.api.interaction.weapon.Gauntlet;
|
||||
import net.Indyuce.mmoitems.api.interaction.projectile.ArrowParticles;
|
||||
import net.Indyuce.mmoitems.api.interaction.weapon.Weapon;
|
||||
import net.Indyuce.mmoitems.api.interaction.weapon.untargeted.Staff;
|
||||
import net.Indyuce.mmoitems.api.interaction.weapon.untargeted.UntargetedWeapon;
|
||||
import net.Indyuce.mmoitems.api.player.PlayerData;
|
||||
import net.Indyuce.mmoitems.api.util.message.Message;
|
||||
import org.bukkit.Bukkit;
|
||||
@ -31,6 +32,7 @@ import org.bukkit.event.Event;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.block.Action;
|
||||
import org.bukkit.event.block.BlockBreakEvent;
|
||||
import org.bukkit.event.entity.EntityShootBowEvent;
|
||||
import org.bukkit.event.inventory.InventoryAction;
|
||||
@ -48,18 +50,17 @@ public class ItemUse implements Listener {
|
||||
// || event.getHand() != EquipmentSlot.HAND
|
||||
return;
|
||||
|
||||
NBTItem item = MythicLib.plugin.getVersion().getWrapper().getNBTItem(event.getItem());
|
||||
if (!item.hasType())
|
||||
return;
|
||||
final NBTItem item = MythicLib.plugin.getVersion().getWrapper().getNBTItem(event.getItem());
|
||||
final Type itemType = Type.get(item);
|
||||
if (itemType == null) return;
|
||||
|
||||
/*
|
||||
* Some consumables must be fully eaten through the vanilla eating
|
||||
* animation and are handled there {@link #handleVanillaEatenConsumables(PlayerItemConsumeEvent)}
|
||||
*/
|
||||
final Player player = event.getPlayer();
|
||||
final UseItem useItem = UseItem.getItem(player, item, item.getType());
|
||||
if (useItem instanceof Consumable && ((Consumable) useItem).hasVanillaEating())
|
||||
return;
|
||||
final UseItem useItem = UseItem.getItem(player, item, itemType);
|
||||
if (useItem instanceof Consumable && ((Consumable) useItem).hasVanillaEating()) return;
|
||||
|
||||
// (BUG FIX) Cancel the event to prevent things like shield blocking
|
||||
if (!useItem.checkItemRequirements()) {
|
||||
@ -68,12 +69,11 @@ public class ItemUse implements Listener {
|
||||
}
|
||||
|
||||
// Commands & consummables
|
||||
if (event.getAction().name().contains("RIGHT_CLICK")) {
|
||||
final boolean rightClick = event.getAction() == Action.RIGHT_CLICK_AIR || event.getAction() == Action.RIGHT_CLICK_BLOCK;
|
||||
if (rightClick) {
|
||||
if (useItem.getPlayerData().getMMOPlayerData().getCooldownMap().isOnCooldown(useItem.getMMOItem())) {
|
||||
final double cd = useItem.getPlayerData().getMMOPlayerData().getCooldownMap().getCooldown(useItem.getMMOItem());
|
||||
Message.ITEM_ON_COOLDOWN
|
||||
.format(ChatColor.RED, "#left#", MythicLib.plugin.getMMOConfig().decimal.format(cd), "#s#", cd >= 2 ? "s" : "")
|
||||
.send(player);
|
||||
Message.ITEM_ON_COOLDOWN.format(ChatColor.RED, "#left#", MythicLib.plugin.getMMOConfig().decimal.format(cd), "#s#", cd >= 2 ? "s" : "").send(player);
|
||||
event.setUseItemInHand(Event.Result.DENY);
|
||||
return;
|
||||
}
|
||||
@ -81,8 +81,7 @@ public class ItemUse implements Listener {
|
||||
if (useItem instanceof Consumable) {
|
||||
event.setUseItemInHand(Event.Result.DENY);
|
||||
Consumable.ConsumableConsumeResult result = ((Consumable) useItem).useOnPlayer(event.getHand(), false);
|
||||
if (result == Consumable.ConsumableConsumeResult.CANCEL)
|
||||
return;
|
||||
if (result == Consumable.ConsumableConsumeResult.CANCEL) return;
|
||||
|
||||
else if (result == Consumable.ConsumableConsumeResult.CONSUME)
|
||||
event.getItem().setAmount(event.getItem().getAmount() - 1);
|
||||
@ -92,48 +91,40 @@ public class ItemUse implements Listener {
|
||||
useItem.executeCommands();
|
||||
}
|
||||
|
||||
// Target free weapon attack
|
||||
if (useItem instanceof UntargetedWeapon) {
|
||||
UntargetedWeapon weapon = (UntargetedWeapon) useItem;
|
||||
if (weapon.getWeaponType().corresponds(event.getAction()))
|
||||
weapon.handleTargetFreeAttack(EquipmentSlot.fromBukkit(event.getHand()));
|
||||
}
|
||||
// Target-free weapon effects
|
||||
if (useItem instanceof Weapon)
|
||||
((Weapon) useItem).handleUntargetedAttack(rightClick, EquipmentSlot.fromBukkit(event.getHand()));
|
||||
}
|
||||
|
||||
@EventHandler(ignoreCancelled = true)
|
||||
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
|
||||
public void meleeAttacks(PlayerAttackEvent event) {
|
||||
|
||||
// Checks if it's a melee attack
|
||||
if (!(event.getAttack() instanceof MeleeAttackMetadata))
|
||||
// Make sure it's a melee attack
|
||||
if (!(event.getAttack() instanceof MeleeAttackMetadata)) return;
|
||||
|
||||
final Player player = event.getPlayer();
|
||||
final ItemStack weaponUsed = player.getInventory().getItem(((MeleeAttackMetadata) event.getAttack()).getHand().toBukkit());
|
||||
final NBTItem item = MythicLib.plugin.getVersion().getWrapper().getNBTItem(weaponUsed);
|
||||
final Type itemType = Type.get(item);
|
||||
if (itemType == null || itemType == Type.BLOCK) return;
|
||||
|
||||
// Prevent melee attacks with non-melee weapons
|
||||
if (!itemType.hasMeleeAttacks()) {
|
||||
event.setCancelled(true);
|
||||
return;
|
||||
|
||||
/*
|
||||
* Must apply attack conditions before apply any effects. the event must
|
||||
* be cancelled before anything is applied
|
||||
*/
|
||||
Player player = event.getPlayer();
|
||||
PlayerData playerData = PlayerData.get(player);
|
||||
ItemStack weaponUsed = player.getInventory().getItem(((MeleeAttackMetadata) event.getAttack()).getHand().toBukkit());
|
||||
NBTItem item = MythicLib.plugin.getVersion().getWrapper().getNBTItem(weaponUsed);
|
||||
|
||||
if (item.hasType() && Type.get(item.getType()) != Type.BLOCK) {
|
||||
Weapon weapon = new Weapon(playerData, item);
|
||||
|
||||
if (weapon.getMMOItem().getType().getItemSet() == TypeSet.RANGE) {
|
||||
event.setCancelled(true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!weapon.checkItemRequirements()) {
|
||||
event.setCancelled(true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!weapon.handleTargetedAttack(event.getAttack(), event.getAttacker(), event.getEntity())) {
|
||||
event.setCancelled(true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Check item requirements
|
||||
final PlayerData playerData = PlayerData.get(player);
|
||||
final Weapon weapon = new Weapon(playerData, item);
|
||||
if (!weapon.checkItemRequirements()) {
|
||||
event.setCancelled(true);
|
||||
return;
|
||||
}
|
||||
|
||||
// Apply melee attack
|
||||
if (!weapon.handleTargetedAttack(event.getAttack(), event.getAttacker(), event.getEntity()))
|
||||
event.setCancelled(true);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
|
||||
@ -142,12 +133,10 @@ public class ItemUse implements Listener {
|
||||
|
||||
final Player player = event.getPlayer();
|
||||
final Block block = event.getBlock();
|
||||
if (player.getGameMode() == GameMode.CREATIVE)
|
||||
return;
|
||||
if (player.getGameMode() == GameMode.CREATIVE) return;
|
||||
|
||||
NBTItem item = MythicLib.plugin.getVersion().getWrapper().getNBTItem(player.getInventory().getItemInMainHand());
|
||||
if (!item.hasType())
|
||||
return;
|
||||
if (!item.hasType()) return;
|
||||
|
||||
Tool tool = new Tool(player, item);
|
||||
if (!tool.checkItemRequirements()) {
|
||||
@ -155,92 +144,74 @@ public class ItemUse implements Listener {
|
||||
return;
|
||||
}
|
||||
|
||||
if (tool.miningEffects(block))
|
||||
event.setCancelled(true);
|
||||
if (tool.miningEffects(block)) event.setCancelled(true);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void rightClickWeaponInteractions(PlayerInteractEntityEvent event) {
|
||||
Player player = event.getPlayer();
|
||||
if (!(event.getRightClicked() instanceof LivingEntity))
|
||||
return;
|
||||
final Player player = event.getPlayer();
|
||||
if (!(event.getRightClicked() instanceof LivingEntity)) return;
|
||||
|
||||
NBTItem item = MythicLib.plugin.getVersion().getWrapper().getNBTItem(player.getInventory().getItemInMainHand());
|
||||
if (!item.hasType())
|
||||
return;
|
||||
final NBTItem item = MythicLib.plugin.getVersion().getWrapper().getNBTItem(player.getInventory().getItem(event.getHand()));
|
||||
final Type itemType = Type.get(item);
|
||||
if (itemType == null) return;
|
||||
|
||||
LivingEntity target = (LivingEntity) event.getRightClicked();
|
||||
if (!UtilityMethods.canTarget(player, target, InteractionType.OFFENSE_ACTION))
|
||||
return;
|
||||
final LivingEntity target = (LivingEntity) event.getRightClicked();
|
||||
if (!UtilityMethods.canTarget(player, target, InteractionType.OFFENSE_ACTION)) return;
|
||||
|
||||
UseItem weapon = UseItem.getItem(player, item, item.getType());
|
||||
if (!weapon.checkItemRequirements())
|
||||
return;
|
||||
// Check for usability
|
||||
final UseItem usableItem = UseItem.getItem(player, item, itemType);
|
||||
if (!usableItem.checkItemRequirements()) return;
|
||||
|
||||
// Special staff attack
|
||||
if (weapon instanceof Staff) {
|
||||
SpecialWeaponAttackEvent attackEvent = new SpecialWeaponAttackEvent(weapon.getPlayerData(), (Weapon) weapon, target);
|
||||
Bukkit.getPluginManager().callEvent(attackEvent);
|
||||
if (!attackEvent.isCancelled())
|
||||
((Staff) weapon).specialAttack(target);
|
||||
}
|
||||
|
||||
// Special gauntlet attack
|
||||
if (weapon instanceof Gauntlet) {
|
||||
SpecialWeaponAttackEvent attackEvent = new SpecialWeaponAttackEvent(weapon.getPlayerData(), (Weapon) weapon, target);
|
||||
Bukkit.getPluginManager().callEvent(attackEvent);
|
||||
if (!attackEvent.isCancelled())
|
||||
((Gauntlet) weapon).specialAttack(target);
|
||||
// Apply type-specific entity interactions
|
||||
final SkillHandler onEntityInteract = usableItem.getMMOItem().getType().onEntityInteract();
|
||||
if (onEntityInteract != null) {
|
||||
SpecialWeaponAttackEvent called = new SpecialWeaponAttackEvent(usableItem.getPlayerData(), (Weapon) usableItem, target);
|
||||
Bukkit.getPluginManager().callEvent(called);
|
||||
if (!called.isCancelled())
|
||||
new SimpleSkill(onEntityInteract).cast(new TriggerMetadata(usableItem.getPlayerData().getMMOPlayerData(), TriggerType.API, target));
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Rewrite this with a custom 'ApplyMMOItemEvent'?
|
||||
@EventHandler
|
||||
public void gemStonesAndItemStacks(InventoryClickEvent event) {
|
||||
Player player = (Player) event.getWhoClicked();
|
||||
if (event.getAction() != InventoryAction.SWAP_WITH_CURSOR)
|
||||
return;
|
||||
final Player player = (Player) event.getWhoClicked();
|
||||
if (event.getAction() != InventoryAction.SWAP_WITH_CURSOR) return;
|
||||
|
||||
NBTItem item = MythicLib.plugin.getVersion().getWrapper().getNBTItem(event.getCursor());
|
||||
if (!item.hasType())
|
||||
return;
|
||||
final NBTItem item = MythicLib.plugin.getVersion().getWrapper().getNBTItem(event.getCursor());
|
||||
final Type type = Type.get(item);
|
||||
if (type == null) return;
|
||||
|
||||
UseItem useItem = UseItem.getItem(player, item, item.getType());
|
||||
if (!useItem.checkItemRequirements())
|
||||
return;
|
||||
final UseItem useItem = UseItem.getItem(player, item, type);
|
||||
if (!useItem.checkItemRequirements()) return;
|
||||
|
||||
if (useItem instanceof ItemSkin) {
|
||||
NBTItem picked = MythicLib.plugin.getVersion().getWrapper().getNBTItem(event.getCurrentItem());
|
||||
if (!picked.hasType())
|
||||
return;
|
||||
if (!picked.hasType()) return;
|
||||
|
||||
ItemSkin.ApplyResult result = ((ItemSkin) useItem).applyOntoItem(picked, Type.get(picked.getType()));
|
||||
if (result.getType() == ItemSkin.ResultType.NONE)
|
||||
return;
|
||||
if (result.getType() == ItemSkin.ResultType.NONE) return;
|
||||
|
||||
event.setCancelled(true);
|
||||
item.getItem().setAmount(item.getItem().getAmount() - 1);
|
||||
|
||||
if (result.getType() == ItemSkin.ResultType.FAILURE)
|
||||
return;
|
||||
if (result.getType() == ItemSkin.ResultType.FAILURE) return;
|
||||
|
||||
event.setCurrentItem(result.getResult());
|
||||
}
|
||||
|
||||
if (useItem instanceof GemStone) {
|
||||
NBTItem picked = MythicLib.plugin.getVersion().getWrapper().getNBTItem(event.getCurrentItem());
|
||||
if (!picked.hasType())
|
||||
return;
|
||||
if (!picked.hasType()) return;
|
||||
|
||||
GemStone.ApplyResult result = ((GemStone) useItem).applyOntoItem(picked, Type.get(picked.getType()));
|
||||
if (result.getType() == GemStone.ResultType.NONE)
|
||||
return;
|
||||
if (result.getType() == GemStone.ResultType.NONE) return;
|
||||
|
||||
event.setCancelled(true);
|
||||
item.getItem().setAmount(item.getItem().getAmount() - 1);
|
||||
|
||||
if (result.getType() == GemStone.ResultType.FAILURE)
|
||||
return;
|
||||
if (result.getType() == GemStone.ResultType.FAILURE) return;
|
||||
|
||||
event.setCurrentItem(result.getResult());
|
||||
}
|
||||
@ -253,17 +224,11 @@ public class ItemUse implements Listener {
|
||||
}
|
||||
|
||||
/**
|
||||
* This handler listens to ALL bow shootings, including both
|
||||
* custom bows from MMOItems AND vanilla bows, since MMOItems needs to
|
||||
* apply on-hit effects like crits, elemental damage... even if the
|
||||
* player is using a vanilla bow.
|
||||
* <p>
|
||||
* Fixing commit 4aec1433
|
||||
* This handler registers arrows from custom MMOItems bows
|
||||
*/
|
||||
@EventHandler
|
||||
public void handleCustomBows(EntityShootBowEvent event) {
|
||||
if (!(event.getProjectile() instanceof AbstractArrow) || !(event.getEntity() instanceof Player))
|
||||
return;
|
||||
if (!(event.getProjectile() instanceof AbstractArrow) || !(event.getEntity() instanceof Player)) return;
|
||||
|
||||
final NBTItem item = NBTItem.get(event.getBow());
|
||||
final Type type = Type.get(item.getType());
|
||||
@ -279,13 +244,17 @@ public class ItemUse implements Listener {
|
||||
// Have to get hand manually because 1.15 and below does not have event.getHand()
|
||||
final ItemStack itemInMainHand = playerData.getPlayer().getInventory().getItemInMainHand();
|
||||
final EquipmentSlot bowSlot = itemInMainHand.isSimilar(event.getBow()) ? EquipmentSlot.MAIN_HAND : EquipmentSlot.OFF_HAND;
|
||||
final ProjectileData projData = MMOItems.plugin.getEntities().registerCustomProjectile(item, playerData.getStats().newTemporary(bowSlot), event.getProjectile(), event.getForce());
|
||||
final ProjectileMetadata proj = ProjectileMetadata.create(playerData.getStats().newTemporary(bowSlot), ProjectileType.ARROW, event.getProjectile());
|
||||
proj.setSourceItem(item);
|
||||
proj.setCustomDamage(true);
|
||||
proj.setDamageMultiplier(event.getForce());
|
||||
if (item.hasTag("MMOITEMS_ARROW_PARTICLES"))
|
||||
new ArrowParticles((AbstractArrow) event.getProjectile(), item);
|
||||
final AbstractArrow arrow = (AbstractArrow) event.getProjectile();
|
||||
|
||||
// Apply arrow velocity
|
||||
final double arrowVelocity = projData.getShooter().getStat("ARROW_VELOCITY");
|
||||
if (arrowVelocity > 0)
|
||||
arrow.setVelocity(arrow.getVelocity().multiply(arrowVelocity));
|
||||
final double arrowVelocity = proj.getShooter().getStat("ARROW_VELOCITY");
|
||||
if (arrowVelocity > 0) arrow.setVelocity(arrow.getVelocity().multiply(arrowVelocity));
|
||||
}
|
||||
}
|
||||
|
||||
@ -295,12 +264,12 @@ public class ItemUse implements Listener {
|
||||
*/
|
||||
@EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
|
||||
public void handleVanillaEatenConsumables(PlayerItemConsumeEvent event) {
|
||||
NBTItem item = MythicLib.plugin.getVersion().getWrapper().getNBTItem(event.getItem());
|
||||
if (!item.hasType())
|
||||
return;
|
||||
final NBTItem item = MythicLib.plugin.getVersion().getWrapper().getNBTItem(event.getItem());
|
||||
final Type itemType = Type.get(item);
|
||||
if (itemType == null) return;
|
||||
|
||||
Player player = event.getPlayer();
|
||||
UseItem useItem = UseItem.getItem(player, item, item.getType());
|
||||
UseItem useItem = UseItem.getItem(player, item, itemType);
|
||||
if (!useItem.checkItemRequirements()) {
|
||||
event.setCancelled(true);
|
||||
return;
|
||||
@ -310,9 +279,7 @@ public class ItemUse implements Listener {
|
||||
|
||||
if (useItem.getPlayerData().getMMOPlayerData().getCooldownMap().isOnCooldown(useItem.getMMOItem())) {
|
||||
final double cd = useItem.getPlayerData().getMMOPlayerData().getCooldownMap().getCooldown(useItem.getMMOItem());
|
||||
Message.ITEM_ON_COOLDOWN
|
||||
.format(ChatColor.RED, "#left#", MythicLib.plugin.getMMOConfig().decimal.format(cd), "#s#", cd >= 2 ? "s" : "")
|
||||
.send(player);
|
||||
Message.ITEM_ON_COOLDOWN.format(ChatColor.RED, "#left#", MythicLib.plugin.getMMOConfig().decimal.format(cd), "#s#", cd >= 2 ? "s" : "").send(player);
|
||||
event.setCancelled(true);
|
||||
return;
|
||||
}
|
||||
@ -326,8 +293,7 @@ public class ItemUse implements Listener {
|
||||
}
|
||||
|
||||
// Item is not consumed but its effects are applied anyways
|
||||
if (result == Consumable.ConsumableConsumeResult.NOT_CONSUME)
|
||||
event.setCancelled(true);
|
||||
if (result == Consumable.ConsumableConsumeResult.NOT_CONSUME) event.setCancelled(true);
|
||||
|
||||
useItem.getPlayerData().getMMOPlayerData().getCooldownMap().applyCooldown(useItem.getMMOItem(), useItem.getNBTItem().getStat("ITEM_COOLDOWN"));
|
||||
useItem.executeCommands();
|
||||
|
@ -11,7 +11,7 @@ import net.Indyuce.mmoitems.api.util.NumericStatFormula;
|
||||
import net.Indyuce.mmoitems.api.util.message.Message;
|
||||
import net.Indyuce.mmoitems.stat.GemUpgradeScaling;
|
||||
import net.Indyuce.mmoitems.stat.LuteAttackEffectStat.LuteAttackEffect;
|
||||
import net.Indyuce.mmoitems.stat.StaffSpiritStat.StaffSpirit;
|
||||
//import net.Indyuce.mmoitems.stat.StaffSpiritStat.StaffSpirit;
|
||||
import net.Indyuce.mmoitems.util.LanguageFile;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
@ -138,9 +138,9 @@ public class ConfigManager implements Reloadable {
|
||||
|
||||
// Staff spirits
|
||||
final LanguageFile attackEffects = new LanguageFile("attack-effects");
|
||||
for (StaffSpirit sp : StaffSpirit.values())
|
||||
/* for (StaffSpirit sp : StaffSpirit.values())
|
||||
sp.setName(attackEffects.computeTranslation("staff-spirit." + sp.name().toLowerCase().replace("_", "-"),
|
||||
() -> UtilityMethods.caseOnWords(sp.name().toLowerCase().replace("_", " "))));
|
||||
() -> UtilityMethods.caseOnWords(sp.name().toLowerCase().replace("_", " "))));*/
|
||||
|
||||
// Lute attack effects
|
||||
for (LuteAttackEffect eff : LuteAttackEffect.values())
|
||||
@ -262,11 +262,11 @@ public class ConfigManager implements Reloadable {
|
||||
public String getLuteAttackEffectName(LuteAttackEffect effect) {
|
||||
return effect.getName();
|
||||
}
|
||||
|
||||
/*
|
||||
@Deprecated
|
||||
public String getStaffSpiritName(StaffSpirit spirit) {
|
||||
return spirit.getName();
|
||||
}
|
||||
}*/
|
||||
|
||||
/**
|
||||
* @deprecated See {@link net.Indyuce.mmoitems.api.item.util.LoreUpdate}
|
||||
|
@ -109,7 +109,7 @@ public class CraftingManager implements Reloadable {
|
||||
|
||||
for (CraftingStation station : stations.values())
|
||||
try {
|
||||
station.postLoad();
|
||||
station.getPostLoadAction().performAction();
|
||||
} catch (IllegalArgumentException exception) {
|
||||
MMOItems.plugin.getLogger().log(Level.WARNING,
|
||||
"Could not post-load station '" + station.getId() + "': " + exception.getMessage());
|
||||
|
@ -1,153 +0,0 @@
|
||||
package net.Indyuce.mmoitems.manager;
|
||||
|
||||
import io.lumine.mythic.lib.api.event.PlayerAttackEvent;
|
||||
import io.lumine.mythic.lib.api.item.NBTItem;
|
||||
import io.lumine.mythic.lib.damage.ProjectileAttackMetadata;
|
||||
import io.lumine.mythic.lib.player.PlayerMetadata;
|
||||
import net.Indyuce.mmoitems.MMOItems;
|
||||
import net.Indyuce.mmoitems.api.interaction.projectile.ArrowParticles;
|
||||
import net.Indyuce.mmoitems.api.interaction.projectile.EntityData;
|
||||
import net.Indyuce.mmoitems.api.interaction.projectile.ProjectileData;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.*;
|
||||
import org.bukkit.enchantments.Enchantment;
|
||||
import org.bukkit.entity.AbstractArrow;
|
||||
import org.bukkit.event.EventHandler;
|
||||
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.ProjectileHitEvent;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.WeakHashMap;
|
||||
|
||||
public class EntityManager implements Listener {
|
||||
|
||||
/**
|
||||
* Entity data used by abilities or staff attacks that utilize entities like
|
||||
* evoker fangs or shulker missiles. It can correspond to the damage the
|
||||
* entity is supposed to deal, etc
|
||||
*/
|
||||
private final Map<Integer, EntityData> entities = new HashMap<>();
|
||||
|
||||
private final Map<Integer, ProjectileData> projectiles = new WeakHashMap<>();
|
||||
|
||||
@Deprecated
|
||||
public void registerCustomProjectile(@NotNull NBTItem sourceItem, @NotNull PlayerMetadata attacker, @NotNull Entity entity, boolean customWeapon, double damageMultiplicator) {
|
||||
registerCustomProjectile(sourceItem, attacker, entity, damageMultiplicator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a custom projectile. This is used for bows, crossbows and tridents.
|
||||
*
|
||||
* @param sourceItem Item used to shoot the projectile
|
||||
* @param attacker Cached stats of the player shooting the projectile
|
||||
* @param entity The custom entity
|
||||
* @param damageMultiplicator The damage coefficient. For bows, this is basically the pull force.
|
||||
* For tridents or anything else this is always set to 1
|
||||
*/
|
||||
@NotNull
|
||||
public ProjectileData registerCustomProjectile(@NotNull NBTItem sourceItem, @NotNull PlayerMetadata attacker, @NotNull Entity entity, double damageMultiplicator) {
|
||||
|
||||
// Initialize projectile data
|
||||
final ProjectileData projectileData = new ProjectileData(attacker, sourceItem, damageMultiplicator);
|
||||
|
||||
/*
|
||||
* Load arrow particles if the entity is an arrow and if the item has
|
||||
* arrow particles. Currently projectiles are only arrows so there is no
|
||||
* problem with other projectiles like snowballs etc.
|
||||
*/
|
||||
if (entity instanceof AbstractArrow && sourceItem.hasTag("MMOITEMS_ARROW_PARTICLES"))
|
||||
new ArrowParticles((AbstractArrow) entity, sourceItem);
|
||||
|
||||
projectiles.put(entity.getEntityId(), projectileData);
|
||||
return projectileData;
|
||||
}
|
||||
|
||||
public void registerCustomEntity(Entity entity, EntityData data) {
|
||||
entities.put(entity.getEntityId(), data);
|
||||
}
|
||||
|
||||
public boolean isCustomProjectile(Projectile projectile) {
|
||||
return projectiles.containsKey(projectile.getEntityId());
|
||||
}
|
||||
|
||||
public boolean isCustomEntity(Entity entity) {
|
||||
return entities.containsKey(entity.getEntityId());
|
||||
}
|
||||
|
||||
public ProjectileData getProjectileData(Projectile projectile) {
|
||||
return Objects.requireNonNull(projectiles.get(projectile.getEntityId()), "Provided entity is not a custom projectile");
|
||||
}
|
||||
|
||||
public EntityData getEntityData(Entity entity) {
|
||||
return Objects.requireNonNull(entities.get(entity.getEntityId()), "Provided entity is not a custom entity");
|
||||
}
|
||||
|
||||
public void unregisterCustomProjectile(Projectile projectile) {
|
||||
projectiles.remove(projectile.getEntityId());
|
||||
}
|
||||
|
||||
public void unregisterCustomEntity(Entity entity) {
|
||||
entities.remove(entity.getEntityId());
|
||||
}
|
||||
|
||||
/**
|
||||
* This event is called on LOWEST and only edits the custom bow base damage.
|
||||
* It does NOT take into account the base damage passed in Bow#getDamage()
|
||||
* and fully overrides any change.
|
||||
*
|
||||
* This applies to tridents, arrows, spectral arrows etc.
|
||||
* <p>
|
||||
* Event order: ProjectileHit -> EntityDamage / EntityDeathEvent
|
||||
*/
|
||||
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
|
||||
public void customProjectileDamage(EntityDamageByEntityEvent event) {
|
||||
if (!(event.getDamager() instanceof Projectile) || !(event.getEntity() instanceof LivingEntity) || event.getEntity().hasMetadata("NPC"))
|
||||
return;
|
||||
|
||||
final Projectile projectile = (Projectile) event.getDamager();
|
||||
final ProjectileData data = projectiles.get(projectile.getEntityId());
|
||||
if (data == null)
|
||||
return;
|
||||
|
||||
// Calculate custom base damage
|
||||
double baseDamage = data.getDamage();
|
||||
|
||||
// Apply power vanilla enchant
|
||||
if (projectile instanceof AbstractArrow && data.getSourceItem().getItem().hasItemMeta()
|
||||
&& data.getSourceItem().getItem().getItemMeta().getEnchants().containsKey(Enchantment.ARROW_DAMAGE))
|
||||
baseDamage *= 1.25 + (.25 * data.getSourceItem().getItem().getItemMeta().getEnchantLevel(Enchantment.ARROW_DAMAGE));
|
||||
|
||||
event.setDamage(baseDamage);
|
||||
}
|
||||
|
||||
@EventHandler(ignoreCancelled = true)
|
||||
public void onHitEffects(PlayerAttackEvent event) {
|
||||
if (!(event.getAttack() instanceof ProjectileAttackMetadata))
|
||||
return;
|
||||
|
||||
final ProjectileAttackMetadata projAttack = (ProjectileAttackMetadata) event.getAttack();
|
||||
final @Nullable ProjectileData data = projectiles.get(projAttack.getProjectile().getEntityId());
|
||||
if (data == null)
|
||||
return;
|
||||
|
||||
// Apply MMOItems specific modifications
|
||||
data.applyPotionEffects(event.getEntity());
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR)
|
||||
public void unregisterProjectileData(ProjectileHitEvent event) {
|
||||
Bukkit.getScheduler().scheduleSyncDelayedTask(MMOItems.plugin, () -> unregisterCustomProjectile(event.getEntity()));
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR)
|
||||
public void unregisterEntityData(EntityDeathEvent event) {
|
||||
Bukkit.getScheduler().scheduleSyncDelayedTask(MMOItems.plugin, () -> unregisterCustomEntity(event.getEntity()));
|
||||
}
|
||||
}
|
@ -6,7 +6,6 @@ import io.lumine.mythic.lib.skill.handler.SkillHandler;
|
||||
import net.Indyuce.mmoitems.MMOItems;
|
||||
import net.Indyuce.mmoitems.api.ConfigFile;
|
||||
import net.Indyuce.mmoitems.skill.RegisteredSkill;
|
||||
import net.Indyuce.mmoitems.skill.ShulkerMissile;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@ -81,8 +80,6 @@ public class SkillManager {
|
||||
if (clearBefore)
|
||||
skills.clear();
|
||||
|
||||
MythicLib.plugin.getSkills().registerSkillHandler(new ShulkerMissile());
|
||||
|
||||
File skillFolder = new File(MMOItems.plugin.getDataFolder() + "/skill");
|
||||
if (!skillFolder.exists()) {
|
||||
|
||||
|
@ -23,6 +23,12 @@ import java.util.logging.Level;
|
||||
public class StatManager {
|
||||
private final Map<String, ItemStat<?, ?>> stats = new LinkedHashMap<>();
|
||||
|
||||
/**
|
||||
* TODO refactor with stat categories
|
||||
*/
|
||||
@Deprecated
|
||||
private final Map<String, ItemStat<?, ?>> legacyAliases = new HashMap<>();
|
||||
|
||||
/*
|
||||
* These lists are sets of stats collected when the stats are registered for
|
||||
* the first time to make their access easier. Check the classes
|
||||
@ -33,11 +39,13 @@ public class StatManager {
|
||||
private final List<ConsumableItemInteraction> consumableActions = new ArrayList<>();
|
||||
private final List<PlayerConsumable> playerConsumables = new ArrayList<>();
|
||||
|
||||
|
||||
/**
|
||||
* Load default stats using java reflection, get all public static final
|
||||
* fields in the ItemStat and register them as stat instances
|
||||
* <p>
|
||||
* TODO refactor
|
||||
*/
|
||||
@Deprecated
|
||||
public void load() {
|
||||
for (Field field : ItemStats.class.getFields())
|
||||
try {
|
||||
@ -53,9 +61,9 @@ public class StatManager {
|
||||
|
||||
/**
|
||||
* @see FictiveNumericStat
|
||||
* @deprecated Needs refactor
|
||||
* <p>
|
||||
* TODO refactor
|
||||
*/
|
||||
@Deprecated
|
||||
public void reload(boolean cleanFirst) {
|
||||
|
||||
// Clean fictive numeric stats before
|
||||
@ -81,10 +89,9 @@ public class StatManager {
|
||||
|
||||
/**
|
||||
* Load custom stats
|
||||
*
|
||||
* @deprecated Needs refactor
|
||||
* <p>
|
||||
* TODO refactor
|
||||
*/
|
||||
@Deprecated
|
||||
public void loadCustom() {
|
||||
ConfigManager.DefaultFile.CUSTOM_STATS.checkFile();
|
||||
ConfigFile config = new ConfigFile("custom-stats");
|
||||
@ -95,10 +102,9 @@ public class StatManager {
|
||||
|
||||
/**
|
||||
* Register all MythicLib elements as stats
|
||||
*
|
||||
* @deprecated Needs refactor
|
||||
* <p>
|
||||
* TODO refactor
|
||||
*/
|
||||
@Deprecated
|
||||
public void loadElements() {
|
||||
for (ElementStatType type : ElementStatType.values())
|
||||
for (Element element : MythicLib.plugin.getElements().getAll())
|
||||
@ -154,11 +160,21 @@ public class StatManager {
|
||||
|
||||
@Nullable
|
||||
public ItemStat<?, ?> get(String id) {
|
||||
ItemStat<?, ?> stat = stats.getOrDefault(id, null);
|
||||
if (stat == null) {
|
||||
stat = numeric.stream().filter(doubleStat -> doubleStat.getId().equals(id)).findFirst().orElse(null);
|
||||
}
|
||||
return stat;
|
||||
|
||||
// Default registry
|
||||
ItemStat<?, ?> stat = stats.get(id);
|
||||
if (stat != null) return stat;
|
||||
|
||||
// Numeric registry (see to-do)
|
||||
stat = numeric.stream().filter(doubleStat -> doubleStat.getId().equals(id)).findFirst().orElse(null);
|
||||
if (stat != null) return stat;
|
||||
|
||||
// Legacy liases
|
||||
stat = legacyAliases.get(id);
|
||||
if (stat != null) return stat;
|
||||
|
||||
// Non existing stat
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -189,9 +205,14 @@ public class StatManager {
|
||||
return;
|
||||
}
|
||||
|
||||
// Main registry
|
||||
stats.put(stat.getId(), stat);
|
||||
|
||||
// Custom registries
|
||||
// Register aliases
|
||||
for (String alias : stat.getAliases())
|
||||
legacyAliases.put(alias, stat);
|
||||
|
||||
// Use-case specific registries
|
||||
if (stat instanceof DoubleStat && !(stat instanceof GemStoneStat) && stat.isCompatible(Type.GEM_STONE))
|
||||
numeric.add((DoubleStat) stat);
|
||||
if (stat instanceof ItemRestriction) itemRestriction.add((ItemRestriction) stat);
|
||||
@ -244,8 +265,7 @@ public class StatManager {
|
||||
|
||||
// Create a new stat instance
|
||||
try {
|
||||
ItemStat<?, ?> stat = statClass.getConstructor(String.class, Material.class, String.class, String[].class, String[].class, Material[].class)
|
||||
.newInstance(statId, Material.PAPER, name, lore, new String[]{"!miscellaneous", "!block", "all"}, new Material[0]);
|
||||
ItemStat<?, ?> stat = statClass.getConstructor(String.class, Material.class, String.class, String[].class, String[].class, Material[].class).newInstance(statId, Material.PAPER, name, lore, new String[]{"!miscellaneous", "!block", "all"}, new Material[0]);
|
||||
register(stat);
|
||||
} catch (InstantiationException | IllegalAccessException | InvocationTargetException |
|
||||
NoSuchMethodException e) {
|
||||
|
@ -172,7 +172,7 @@ public class TemplateManager implements Reloadable {
|
||||
|
||||
try {
|
||||
MMOItemTemplate template = new MMOItemTemplate(type, type.getConfigFile().getConfig().getConfigurationSection(id));
|
||||
template.postLoad();
|
||||
template.getPostLoadAction().performAction();
|
||||
registerTemplate(template);
|
||||
return template;
|
||||
|
||||
@ -327,7 +327,7 @@ public class TemplateManager implements Reloadable {
|
||||
ffp.log(FriendlyFeedbackCategory.INFORMATION, "Loading item templates, please wait...");
|
||||
templates.forEach(template -> {
|
||||
try {
|
||||
template.postLoad();
|
||||
template.getPostLoadAction().performAction();
|
||||
} catch (IllegalArgumentException exception) {
|
||||
ffp.activatePrefix(true, "Item Templates \u00a78($r" + template.getType().getId() + "\u00a78)");
|
||||
ffp.log(FriendlyFeedbackCategory.INFORMATION, "Could not post-load item template '" + template.getId() + "': " + exception.getMessage());
|
||||
|
@ -5,6 +5,8 @@ import net.Indyuce.mmoitems.api.ConfigFile;
|
||||
import net.Indyuce.mmoitems.api.Type;
|
||||
import net.Indyuce.mmoitems.manager.ConfigManager.DefaultFile;
|
||||
import org.apache.commons.lang.Validate;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.configuration.file.FileConfiguration;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@ -13,100 +15,112 @@ import java.lang.reflect.Modifier;
|
||||
import java.util.*;
|
||||
import java.util.logging.Level;
|
||||
|
||||
public class TypeManager implements Reloadable {
|
||||
private final Map<String, Type> map = new LinkedHashMap<>();
|
||||
public class TypeManager {
|
||||
private final Map<String, Type> map = new LinkedHashMap<>();
|
||||
|
||||
/**
|
||||
* Reloads the type manager. It entirely empties the currently registered
|
||||
* item types, registers default item types again and reads item-types.yml
|
||||
*/
|
||||
public void reload() {
|
||||
map.clear();
|
||||
/**
|
||||
* Reloads the type manager. It entirely empties the currently registered
|
||||
* item types, registers default item types again and reads item-types.yml
|
||||
*/
|
||||
public void reload(boolean clearBefore) {
|
||||
if (clearBefore) map.clear();
|
||||
|
||||
// Load default types
|
||||
for (Field field : Type.class.getFields())
|
||||
try {
|
||||
if (Modifier.isStatic(field.getModifiers()) && Modifier.isFinal(field.getModifiers()) && field.get(null) instanceof Type)
|
||||
register((Type) field.get(null));
|
||||
} catch (Exception exception) {
|
||||
MMOItems.plugin.getLogger().log(Level.WARNING, "Couldn't register type called '" + field.getName() + "': " + exception.getMessage());
|
||||
}
|
||||
// Load default types
|
||||
for (Field field : Type.class.getFields())
|
||||
try {
|
||||
if (Modifier.isStatic(field.getModifiers()) && Modifier.isFinal(field.getModifiers()) && field.get(null) instanceof Type)
|
||||
register((Type) field.get(null));
|
||||
} catch (Exception exception) {
|
||||
MMOItems.plugin.getLogger().log(Level.WARNING, "Couldn't register type called '" + field.getName() + "': " + exception.getMessage());
|
||||
}
|
||||
|
||||
/*
|
||||
* Register all other types. Important: check if the map already
|
||||
* contains the id, this way the DEFAULT types are not registered twice,
|
||||
* and only custom types are registered with a parent.
|
||||
*/
|
||||
DefaultFile.ITEM_TYPES.checkFile();
|
||||
// Load custom types
|
||||
DefaultFile.ITEM_TYPES.checkFile();
|
||||
FileConfiguration config = new ConfigFile("item-types").getConfig();
|
||||
for (String id : config.getKeys(false))
|
||||
if (!map.containsKey(id))
|
||||
try {
|
||||
register(new Type(this, config.getConfigurationSection(id)));
|
||||
} catch (IllegalArgumentException exception) {
|
||||
MMOItems.plugin.getLogger().log(Level.WARNING, "Could not register type '" + id + "': " + exception.getMessage());
|
||||
}
|
||||
|
||||
ConfigFile config = new ConfigFile("item-types");
|
||||
for (String id : config.getConfig().getKeys(false))
|
||||
if (!map.containsKey(id))
|
||||
try {
|
||||
register(new Type(this, config.getConfig().getConfigurationSection(id)));
|
||||
} catch (IllegalArgumentException exception) {
|
||||
MMOItems.plugin.getLogger().log(Level.WARNING, "Could not register type '" + id + "': " + exception.getMessage());
|
||||
}
|
||||
for (Iterator<Type> iterator = map.values().iterator(); iterator.hasNext(); ) {
|
||||
Type type = iterator.next();
|
||||
|
||||
for (Iterator<Type> iterator = map.values().iterator(); iterator.hasNext();) {
|
||||
Type type = iterator.next();
|
||||
try {
|
||||
ConfigurationSection section = config.getConfigurationSection(type.getId());
|
||||
Validate.notNull(section, "Could not find config section for type '" + type.getId() + "'");
|
||||
type.load(section);
|
||||
if (clearBefore) type.getPostLoadAction().performAction();
|
||||
} catch (RuntimeException exception) {
|
||||
MMOItems.plugin.getLogger().log(Level.WARNING, "Could not register type '" + type.getId() + "': " + exception.getMessage());
|
||||
iterator.remove();
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
type.load(config.getConfig().getConfigurationSection(type.getId()));
|
||||
} catch (IllegalArgumentException exception) {
|
||||
MMOItems.plugin.getLogger().log(Level.WARNING, "Could not register type '" + type.getId() + "': " + exception.getMessage());
|
||||
iterator.remove();
|
||||
continue;
|
||||
}
|
||||
/*
|
||||
* caches all the stats which the type can have to reduce future
|
||||
* both item generation (and GUI) calculations. probably the thing
|
||||
* which takes the most time when loading item types.
|
||||
*/
|
||||
type.getAvailableStats().clear();
|
||||
MMOItems.plugin.getStats().getAll().stream().filter(stat -> stat.isCompatible(type)).forEach(stat -> type.getAvailableStats().add(stat));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* caches all the stats which the type can have to reduce future
|
||||
* both item generation (and GUI) calculations. probably the thing
|
||||
* which takes the most time when loading item types.
|
||||
*/
|
||||
type.getAvailableStats().clear();
|
||||
MMOItems.plugin.getStats().getAll().stream().filter(stat -> stat.isCompatible(type)).forEach(stat -> type.getAvailableStats().add(stat));
|
||||
}
|
||||
}
|
||||
public void postload() {
|
||||
for (Type type : map.values())
|
||||
try {
|
||||
type.getPostLoadAction().performAction();
|
||||
} catch (RuntimeException exception) {
|
||||
MMOItems.plugin.getLogger().log(Level.WARNING, "An error occured while post-loading type '" + type.getId() + "': " + exception.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public void register(Type type) {
|
||||
map.put(type.getId(), type);
|
||||
}
|
||||
public void register(Type type) {
|
||||
map.put(type.getId(), type);
|
||||
}
|
||||
|
||||
public void registerAll(Type... types) {
|
||||
for (Type type : types)
|
||||
register(type);
|
||||
}
|
||||
public void registerAll(Type... types) {
|
||||
for (Type type : types)
|
||||
register(type);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param id Internal ID of the type
|
||||
*
|
||||
* @return The MMOItem Type if it found.
|
||||
*/
|
||||
@Nullable public Type get(@Nullable String id) {
|
||||
if (id == null) { return null; }
|
||||
return map.get(id);
|
||||
}
|
||||
/**
|
||||
* @param id Internal ID of the type
|
||||
* @return The MMOItem Type if it found.
|
||||
*/
|
||||
@Nullable
|
||||
public Type get(@Nullable String id) {
|
||||
if (id == null) {
|
||||
return null;
|
||||
}
|
||||
return map.get(id);
|
||||
}
|
||||
|
||||
@NotNull public Type getOrThrow(@Nullable String id) {
|
||||
Validate.isTrue(map.containsKey(id), "Could not find item type with ID '" + id + "'");
|
||||
return map.get(id);
|
||||
}
|
||||
@NotNull
|
||||
public Type getOrThrow(@Nullable String id) {
|
||||
Validate.isTrue(map.containsKey(id), "Could not find item type with ID '" + id + "'");
|
||||
return map.get(id);
|
||||
}
|
||||
|
||||
public boolean has(String id) {
|
||||
return map.containsKey(id);
|
||||
}
|
||||
public boolean has(String id) {
|
||||
return map.containsKey(id);
|
||||
}
|
||||
|
||||
public Collection<Type> getAll() {
|
||||
return map.values();
|
||||
}
|
||||
public Collection<Type> getAll() {
|
||||
return map.values();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The names of all loaded types.
|
||||
*/
|
||||
public ArrayList<String> getAllTypeNames() {
|
||||
ArrayList<String> ret = new ArrayList<>();
|
||||
for (Type t : getAll()) { ret.add(t.getId()); }
|
||||
return ret;
|
||||
}
|
||||
/**
|
||||
* @return The names of all loaded types.
|
||||
*/
|
||||
public ArrayList<String> getAllTypeNames() {
|
||||
ArrayList<String> ret = new ArrayList<>();
|
||||
for (Type t : getAll()) {
|
||||
ret.add(t.getId());
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
@ -1,146 +0,0 @@
|
||||
package net.Indyuce.mmoitems.skill;
|
||||
|
||||
import io.lumine.mythic.lib.UtilityMethods;
|
||||
import io.lumine.mythic.lib.api.item.NBTItem;
|
||||
import io.lumine.mythic.lib.comp.interaction.InteractionType;
|
||||
import io.lumine.mythic.lib.damage.DamageMetadata;
|
||||
import io.lumine.mythic.lib.damage.DamageType;
|
||||
import io.lumine.mythic.lib.player.PlayerMetadata;
|
||||
import io.lumine.mythic.lib.skill.SkillMetadata;
|
||||
import io.lumine.mythic.lib.skill.handler.SkillHandler;
|
||||
import io.lumine.mythic.lib.skill.result.def.VectorSkillResult;
|
||||
import net.Indyuce.mmoitems.MMOItems;
|
||||
import net.Indyuce.mmoitems.api.interaction.projectile.EntityData;
|
||||
import org.bukkit.Color;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Particle;
|
||||
import org.bukkit.Sound;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.entity.ShulkerBullet;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.entity.EntityDamageByEntityEvent;
|
||||
import org.bukkit.potion.PotionEffect;
|
||||
import org.bukkit.potion.PotionEffectType;
|
||||
import org.bukkit.scheduler.BukkitRunnable;
|
||||
import org.bukkit.util.Vector;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class ShulkerMissile extends SkillHandler<VectorSkillResult> implements Listener {
|
||||
public ShulkerMissile() {
|
||||
super("SHULKER_MISSILE");
|
||||
|
||||
registerModifiers("damage", "effect-duration", "duration");
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public VectorSkillResult getResult(SkillMetadata meta) {
|
||||
return new VectorSkillResult(meta);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void whenCast(VectorSkillResult result, SkillMetadata skillMeta) {
|
||||
double duration = skillMeta.getParameter("duration");
|
||||
|
||||
Player caster = skillMeta.getCaster().getPlayer();
|
||||
|
||||
new BukkitRunnable() {
|
||||
double n = 0;
|
||||
|
||||
public void run() {
|
||||
if (n++ > 3) {
|
||||
cancel();
|
||||
return;
|
||||
}
|
||||
|
||||
Vector vec = result.getTarget();
|
||||
caster.getWorld().playSound(caster.getLocation(), Sound.ENTITY_WITHER_SHOOT, 2, 2);
|
||||
ShulkerBullet shulkerBullet = (ShulkerBullet) caster.getWorld().spawnEntity(caster.getLocation().add(0, 1, 0),
|
||||
EntityType.SHULKER_BULLET);
|
||||
shulkerBullet.setShooter(caster);
|
||||
|
||||
MMOItems.plugin.getEntities().registerCustomEntity(shulkerBullet, new ShulkerMissileEntityData(skillMeta.getCaster(), new DamageMetadata(skillMeta.getParameter("damage"), DamageType.SKILL, DamageType.MAGIC, DamageType.PROJECTILE), skillMeta.getParameter("effect-duration"), null));
|
||||
|
||||
new BukkitRunnable() {
|
||||
double ti = 0;
|
||||
|
||||
public void run() {
|
||||
if (shulkerBullet.isDead() || ti++ >= duration * 20) {
|
||||
shulkerBullet.remove();
|
||||
cancel();
|
||||
} else
|
||||
shulkerBullet.setVelocity(vec);
|
||||
}
|
||||
}.runTaskTimer(MMOItems.plugin, 0, 1);
|
||||
}
|
||||
}.runTaskTimer(MMOItems.plugin, 0, 3);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void a(EntityDamageByEntityEvent event) {
|
||||
if (event.getDamager() instanceof ShulkerBullet && event.getEntity() instanceof LivingEntity) {
|
||||
ShulkerBullet damager = (ShulkerBullet) event.getDamager();
|
||||
LivingEntity entity = (LivingEntity) event.getEntity();
|
||||
if (!MMOItems.plugin.getEntities().isCustomEntity(damager))
|
||||
return;
|
||||
|
||||
ShulkerMissileEntityData data = (ShulkerMissileEntityData) MMOItems.plugin.getEntities().getEntityData(damager);
|
||||
if (!UtilityMethods.canTarget(data.caster.getPlayer(), null, entity, data.isWeaponAttack() ? InteractionType.OFFENSE_ACTION : InteractionType.OFFENSE_SKILL)) {
|
||||
event.setCancelled(true);
|
||||
return;
|
||||
}
|
||||
|
||||
event.setDamage(data.damage.getDamage());
|
||||
|
||||
new BukkitRunnable() {
|
||||
final Location loc = entity.getLocation();
|
||||
double y = 0;
|
||||
|
||||
public void run() {
|
||||
|
||||
// Potion effect should apply right after the damage with a 1 tick delay.
|
||||
if (y == 0) {
|
||||
entity.removePotionEffect(PotionEffectType.LEVITATION);
|
||||
entity.addPotionEffect(new PotionEffect(PotionEffectType.LEVITATION, (int) (data.duration * 20), 0));
|
||||
}
|
||||
|
||||
for (int j1 = 0; j1 < 3; j1++) {
|
||||
y += .04;
|
||||
for (int j = 0; j < 2; j++) {
|
||||
double xz = y * Math.PI * 1.3 + (j * Math.PI);
|
||||
loc.getWorld().spawnParticle(Particle.REDSTONE, loc.clone().add(Math.cos(xz), y, Math.sin(xz)), 1,
|
||||
new Particle.DustOptions(Color.MAROON, 1));
|
||||
}
|
||||
}
|
||||
if (y >= 2)
|
||||
cancel();
|
||||
}
|
||||
}.runTaskTimer(MMOItems.plugin, 0, 1);
|
||||
}
|
||||
}
|
||||
|
||||
public static class ShulkerMissileEntityData implements EntityData {
|
||||
private final PlayerMetadata caster;
|
||||
private final DamageMetadata damage;
|
||||
private final double duration;
|
||||
|
||||
@Nullable
|
||||
private final NBTItem weapon;
|
||||
|
||||
public ShulkerMissileEntityData(PlayerMetadata caster, DamageMetadata damage, double duration, NBTItem weapon) {
|
||||
this.caster = caster;
|
||||
this.damage = damage;
|
||||
this.duration = duration;
|
||||
this.weapon = weapon;
|
||||
}
|
||||
|
||||
public boolean isWeaponAttack() {
|
||||
return damage.hasType(DamageType.WEAPON);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,62 @@
|
||||
package net.Indyuce.mmoitems.stat;
|
||||
|
||||
import io.lumine.mythic.lib.MythicLib;
|
||||
import io.lumine.mythic.lib.UtilityMethods;
|
||||
import io.lumine.mythic.lib.api.item.ItemTag;
|
||||
import io.lumine.mythic.lib.api.item.SupportedNBTTagValues;
|
||||
import net.Indyuce.mmoitems.MMOItems;
|
||||
import net.Indyuce.mmoitems.api.item.build.ItemStackBuilder;
|
||||
import net.Indyuce.mmoitems.api.item.mmoitem.ReadMMOItem;
|
||||
import net.Indyuce.mmoitems.gui.edition.EditionInventory;
|
||||
import net.Indyuce.mmoitems.stat.data.StringData;
|
||||
import net.Indyuce.mmoitems.stat.type.StringStat;
|
||||
import org.bukkit.Material;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class ActionLeftClick extends StringStat {
|
||||
public ActionLeftClick() {
|
||||
super("ON_LEFT_CLICK", Material.COMMAND_BLOCK_MINECART, "Left Click Action", new String[]{"ID of skill ran when left clicking. When used,", "The item will naturally apply item costs like", "mana, stamina, cooldown. This option overrides the", "script provided by the item type."}, new String[]{"weapon"});
|
||||
|
||||
// Staff spirit set as alias
|
||||
setAliases(LEGACY_ID);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void whenInput(@NotNull EditionInventory inv, @NotNull String message, Object... info) {
|
||||
final String format = UtilityMethods.enumName(message);
|
||||
MythicLib.plugin.getSkills().getHandlerOrThrow(format);
|
||||
inv.getEditedSection().set(getPath(), format);
|
||||
inv.registerTemplateEdition();
|
||||
inv.getPlayer().sendMessage(MMOItems.plugin.getPrefix() + getName() + " successfully changed to '" + format + "'");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void whenApplied(@NotNull ItemStackBuilder item, @NotNull StringData data) {
|
||||
item.addItemTag(new ItemTag(getNBTPath(), UtilityMethods.enumName(data.toString())));
|
||||
// No lore insertion
|
||||
}
|
||||
|
||||
public static final String LEGACY_ID = "STAFF_SPIRIT";
|
||||
public static final String LEGACY_PATH = "MMOITEMS_" + LEGACY_ID;
|
||||
|
||||
// TODO refactor with stat categories
|
||||
@Override
|
||||
@Deprecated
|
||||
public void whenLoaded(@NotNull ReadMMOItem mmoitem) {
|
||||
ArrayList<ItemTag> relevantTags = new ArrayList<>();
|
||||
|
||||
// New path
|
||||
if (mmoitem.getNBT().hasTag(getNBTPath()))
|
||||
relevantTags.add(ItemTag.getTagAtPath(getNBTPath(), mmoitem.getNBT(), SupportedNBTTagValues.STRING));
|
||||
|
||||
// Legacy path
|
||||
if (mmoitem.getNBT().hasTag(LEGACY_PATH))
|
||||
relevantTags.add(new ItemTag(getNBTPath(), ItemTag.getTagAtPath(LEGACY_PATH, mmoitem.getNBT(), SupportedNBTTagValues.STRING).getValue()));
|
||||
|
||||
StringData bakedData = getLoadedNBT(relevantTags);
|
||||
if (bakedData != null) mmoitem.setData(this, bakedData);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,34 @@
|
||||
package net.Indyuce.mmoitems.stat;
|
||||
|
||||
import io.lumine.mythic.lib.MythicLib;
|
||||
import io.lumine.mythic.lib.UtilityMethods;
|
||||
import io.lumine.mythic.lib.api.item.ItemTag;
|
||||
import net.Indyuce.mmoitems.MMOItems;
|
||||
import net.Indyuce.mmoitems.api.item.build.ItemStackBuilder;
|
||||
import net.Indyuce.mmoitems.gui.edition.EditionInventory;
|
||||
import net.Indyuce.mmoitems.stat.data.StringData;
|
||||
import net.Indyuce.mmoitems.stat.type.StringStat;
|
||||
import org.bukkit.Material;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class ActionRightClick extends StringStat {
|
||||
public ActionRightClick() {
|
||||
super("ON_RIGHT_CLICK", Material.COMMAND_BLOCK_MINECART, "Right Click Action", new String[]{"ID of skill ran when right clicking. When used,", "The item will naturally apply item costs like", "mana, stamina, cooldown. This option overrides the", "script provided by the item type."}, new String[]{"weapon"});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void whenInput(@NotNull EditionInventory inv, @NotNull String message, Object... info) {
|
||||
final String format = UtilityMethods.enumName(message);
|
||||
MythicLib.plugin.getSkills().getHandlerOrThrow(format);
|
||||
inv.getEditedSection().set(getPath(), format);
|
||||
inv.registerTemplateEdition();
|
||||
inv.getPlayer().sendMessage(MMOItems.plugin.getPrefix() + getName() + " successfully changed to '" + format + "'");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void whenApplied(@NotNull ItemStackBuilder item, @NotNull StringData data) {
|
||||
item.addItemTag(new ItemTag(getNBTPath(), UtilityMethods.enumName(data.toString())));
|
||||
// No lore insertion
|
||||
}
|
||||
}
|
||||
|
@ -20,7 +20,7 @@ import net.Indyuce.mmoitems.stat.data.SkullTextureData;
|
||||
import net.Indyuce.mmoitems.stat.type.BooleanStat;
|
||||
import net.Indyuce.mmoitems.stat.type.ConsumableItemInteraction;
|
||||
import net.Indyuce.mmoitems.util.MMOUtils;
|
||||
import org.apache.commons.lang3.Validate;
|
||||
import org.apache.commons.lang.Validate;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.entity.Player;
|
||||
@ -103,7 +103,7 @@ public class CanDeskin extends BooleanStat implements ConsumableItemInteraction
|
||||
// Try to find the skin item.
|
||||
// This is for backwards compatibility as cases with SKIN subtypes were not handled
|
||||
// in the past, inducing an unfixable data loss for item skins applied onto items
|
||||
@BackwardsCompatibility(version = "unknown") final String skinTypeId = target.getString(ItemSkin.SKIN_TYPE_TAG);
|
||||
@Deprecated final String skinTypeId = target.getString(ItemSkin.SKIN_TYPE_TAG);
|
||||
final Type type = Objects.requireNonNullElse(Type.get(skinTypeId), Type.SKIN);
|
||||
Validate.notNull(type, "Could not find item type of applied skin");
|
||||
final MMOItemTemplate template = MMOItems.plugin.getTemplates().getTemplateOrThrow(Type.SKIN, skinId);
|
||||
|
@ -36,7 +36,7 @@ import java.util.*;
|
||||
public class Elements extends ItemStat<RandomElementListData, ElementListData> implements Previewable<RandomElementListData, ElementListData> {
|
||||
public Elements() {
|
||||
super("ELEMENT", Material.SLIME_BALL, "Elements", new String[]{"The elements of your item."},
|
||||
new String[]{"slashing", "piercing", "blunt", "catalyst", "range", "tool", "armor", "gem_stone"});
|
||||
new String[]{"weapon", "catalyst", "tool", "armor", "gem_stone"});
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -33,7 +33,7 @@ import java.util.Optional;
|
||||
public class GemSockets extends ItemStat<GemSocketsData, GemSocketsData> {
|
||||
public GemSockets() {
|
||||
super("GEM_SOCKETS", Material.EMERALD, "Gem Sockets", new String[]{"The amount of gem", "sockets your weapon has."},
|
||||
new String[]{"piercing", "slashing", "blunt", "catalyst", "range", "tool", "armor", "accessory", "!gem_stone"});
|
||||
new String[]{"weapon", "catalyst", "tool", "armor", "accessory", "!gem_stone"});
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -18,7 +18,6 @@ import org.bukkit.event.inventory.InventoryClickEvent;
|
||||
import net.Indyuce.mmoitems.ItemStats;
|
||||
import net.Indyuce.mmoitems.MMOItems;
|
||||
import net.Indyuce.mmoitems.api.Type;
|
||||
import net.Indyuce.mmoitems.api.TypeSet;
|
||||
import net.Indyuce.mmoitems.api.edition.StatEdition;
|
||||
import net.Indyuce.mmoitems.api.item.build.ItemStackBuilder;
|
||||
import net.Indyuce.mmoitems.gui.edition.EditionInventory;
|
||||
@ -195,10 +194,6 @@ public class ItemTypeRestriction extends ItemStat<StringListData, StringListData
|
||||
if (type.getId().equals(format))
|
||||
return true;
|
||||
|
||||
for (TypeSet set : TypeSet.values())
|
||||
if (set.name().equals(format))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -24,7 +24,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
public class ManaCost extends DoubleStat implements ItemRestriction, PlayerConsumable {
|
||||
|
||||
public ManaCost() {
|
||||
super("MANA_COST", VersionMaterial.LAPIS_LAZULI.toMaterial(), "Mana Cost", new String[]{"Mana spent by your weapon to be used."}, new String[]{"piercing", "slashing", "blunt", "range"});
|
||||
super("MANA_COST", VersionMaterial.LAPIS_LAZULI.toMaterial(), "Mana Cost", new String[]{"Mana spent by your weapon to be used."}, new String[]{"weapon"});
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,94 +0,0 @@
|
||||
package net.Indyuce.mmoitems.stat;
|
||||
|
||||
import io.lumine.mythic.lib.UtilityMethods;
|
||||
import io.lumine.mythic.lib.api.item.ItemTag;
|
||||
import io.lumine.mythic.lib.api.item.NBTItem;
|
||||
import io.lumine.mythic.lib.version.VersionMaterial;
|
||||
import net.Indyuce.mmoitems.MMOItems;
|
||||
import net.Indyuce.mmoitems.api.interaction.weapon.untargeted.staff.*;
|
||||
import net.Indyuce.mmoitems.api.item.build.ItemStackBuilder;
|
||||
import net.Indyuce.mmoitems.gui.edition.EditionInventory;
|
||||
import net.Indyuce.mmoitems.stat.data.StringData;
|
||||
import net.Indyuce.mmoitems.stat.type.StringStat;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
|
||||
public class StaffSpiritStat extends StringStat {
|
||||
public StaffSpiritStat() {
|
||||
super("STAFF_SPIRIT", VersionMaterial.BONE_MEAL.toMaterial(), "Staff Spirit",
|
||||
new String[]{"Spirit changes the texture", "of the magic attack.", "&9Tip: /mi list spirit"}, new String[]{"staff", "wand"});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void whenInput(@NotNull EditionInventory inv, @NotNull String message, Object... info) {
|
||||
try {
|
||||
StaffSpirit spirit = StaffSpirit.valueOf(message.toUpperCase().replace(" ", "_").replace("-", "_"));
|
||||
inv.getEditedSection().set("staff-spirit", spirit.name());
|
||||
inv.registerTemplateEdition();
|
||||
inv.getPlayer().sendMessage(MMOItems.plugin.getPrefix() + "Staff Spirit successfully changed to " + spirit.getName() + ".");
|
||||
} catch (IllegalArgumentException exception) {
|
||||
throw new IllegalArgumentException(exception.getMessage() + " (See all Staff Spirits here: /mi list spirit).");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void whenApplied(@NotNull ItemStackBuilder item, @NotNull StringData data) {
|
||||
StaffSpirit staffSpirit = StaffSpirit.valueOf(data.toString().toUpperCase().replace(" ", "_").replace("-", "_"));
|
||||
item.addItemTag(new ItemTag("MMOITEMS_STAFF_SPIRIT", staffSpirit.name()));
|
||||
item.getLore().insert("staff-spirit", staffSpirit.getName());
|
||||
}
|
||||
|
||||
public enum StaffSpirit {
|
||||
NETHER_SPIRIT("Shoots fire beams.", new NetherSpirit()),
|
||||
VOID_SPIRIT("Shoots shulker missiles.", new VoidSpirit()),
|
||||
MANA_SPIRIT("Summons mana bolts.", new ManaSpirit()),
|
||||
LIGHTNING_SPIRIT("Summons lightning bolts.", new LightningSpirit()),
|
||||
XRAY_SPIRIT("Fires piercing & powerful X-rays.", new XRaySpirit()),
|
||||
THUNDER_SPIRIT("Fires AoE damaging thunder strikes.", new ThunderSpirit()),
|
||||
SUNFIRE_SPIRIT("Fires AoE damaging fire comets.", new SunfireSpirit()),
|
||||
// CURSED_SPIRIT(ChatColor.DARK_PURPLE, "Cursed Spirit", "Fires a
|
||||
// targeted cursed projectile."), new CursedSpirit()),
|
||||
;
|
||||
|
||||
private final String defaultLore;
|
||||
private final StaffAttackHandler handler;
|
||||
|
||||
@NotNull
|
||||
private String name = UtilityMethods.caseOnWords(name().toLowerCase().replace("_", " "));
|
||||
|
||||
StaffSpirit(String description, StaffAttackHandler handler) {
|
||||
this.defaultLore = description;
|
||||
this.handler = handler;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static StaffSpirit get(NBTItem item) {
|
||||
try {
|
||||
return StaffSpirit.valueOf(item.getString("MMOITEMS_STAFF_SPIRIT"));
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public boolean hasLore() {
|
||||
return defaultLore != null;
|
||||
}
|
||||
|
||||
public String getDefaultLore() {
|
||||
return defaultLore;
|
||||
}
|
||||
|
||||
public StaffAttackHandler getAttack() {
|
||||
return handler;
|
||||
}
|
||||
|
||||
public void setName(String str) {
|
||||
this.name = str;
|
||||
}
|
||||
}
|
||||
}
|
@ -49,7 +49,7 @@ public class UpgradeStat extends ItemStat<UpgradeData, UpgradeData> implements C
|
||||
super("UPGRADE", Material.FLINT, "Item Upgrading",
|
||||
new String[] { "Upgrading your item improves its", "current stats. It requires either a", "consumable or a specific crafting ",
|
||||
"station. Upgrading may sometimes &cfail&7..." },
|
||||
new String[] { "piercing", "slashing", "blunt", "catalyst", "range", "tool", "armor", "consumable", "accessory" });
|
||||
new String[] { "weapon", "catalyst", "tool", "armor", "consumable", "accessory" });
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -29,6 +29,9 @@ public abstract class ItemStat<R extends RandomStatData<S>, S extends StatData>
|
||||
private final List<String> compatibleTypes;
|
||||
private final List<Material> compatibleMaterials;
|
||||
|
||||
@Nullable
|
||||
private String[] aliases = {};
|
||||
|
||||
/**
|
||||
* The stat can be enabled or not, depending on the server version to
|
||||
* prevent from displaying useless editable stats in the edition menu.
|
||||
@ -193,6 +196,25 @@ public abstract class ItemStat<R extends RandomStatData<S>, S extends StatData>
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mainly for backwards compatibility. Aliases are basically
|
||||
* other string identifiers that point to the same item stat.
|
||||
* Useful when changing stat keys inside the item configs.
|
||||
*
|
||||
* Aliases have to follow the UPPER_CASE stat identifier format.
|
||||
*/
|
||||
@Nullable
|
||||
public String[] getAliases() {
|
||||
return aliases;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see #getAliases()
|
||||
*/
|
||||
public void setAliases(String... aliases) {
|
||||
this.aliases = aliases;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The stat ID
|
||||
* @deprecated Use getId() instead. Type is no longer an util since they can
|
||||
@ -234,6 +256,7 @@ public abstract class ItemStat<R extends RandomStatData<S>, S extends StatData>
|
||||
return lore;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public List<String> getCompatibleTypes() {
|
||||
return compatibleTypes;
|
||||
}
|
||||
@ -242,11 +265,17 @@ public abstract class ItemStat<R extends RandomStatData<S>, S extends StatData>
|
||||
* @param type The item type to check
|
||||
* @return If a certain item type is compatible with this item stat
|
||||
*/
|
||||
public boolean isCompatible(Type type) {
|
||||
String lower = type.getId().toLowerCase();
|
||||
return type.isSubtype() ? isCompatible(type.getParent())
|
||||
: !compatibleTypes.contains("!" + lower) && (compatibleTypes.contains("all") || compatibleTypes.contains(lower)
|
||||
|| compatibleTypes.contains(type.getItemSet().getName().toLowerCase()));
|
||||
public boolean isCompatible(@NotNull Type type) {
|
||||
|
||||
// Special rule for weapons
|
||||
if (type.isWeapon() && compatibleTypes.contains("weapon")) return true;
|
||||
|
||||
// Recursive call with root types
|
||||
if (type.isSubtype()) return isCompatible(type.getParent());
|
||||
|
||||
// Parent item types
|
||||
final String lower = type.getId().toLowerCase();
|
||||
return !compatibleTypes.contains("!" + lower) && (compatibleTypes.contains("all") || compatibleTypes.contains(lower));
|
||||
}
|
||||
|
||||
public boolean hasValidMaterial(ItemStack item) {
|
||||
|
@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>MMOItems</artifactId>
|
||||
<groupId>net.Indyuce</groupId>
|
||||
<version>6.9.5-SNAPSHOT</version>
|
||||
<version>6.10-SNAPSHOT</version>
|
||||
</parent>
|
||||
<packaging>jar</packaging>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
@ -28,7 +28,7 @@
|
||||
<dependency>
|
||||
<groupId>net.Indyuce</groupId>
|
||||
<artifactId>MMOItems-API</artifactId>
|
||||
<version>6.9.5-SNAPSHOT</version>
|
||||
<version>6.10-SNAPSHOT</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
|
@ -1,18 +1,25 @@
|
||||
package net.Indyuce.mmoitems.listener;
|
||||
|
||||
import io.lumine.mythic.lib.MythicLib;
|
||||
import io.lumine.mythic.lib.api.event.PlayerAttackEvent;
|
||||
import io.lumine.mythic.lib.api.event.armorequip.ArmorEquipEvent;
|
||||
import io.lumine.mythic.lib.api.item.NBTItem;
|
||||
import io.lumine.mythic.lib.api.player.EquipmentSlot;
|
||||
import io.lumine.mythic.lib.damage.ProjectileAttackMetadata;
|
||||
import io.lumine.mythic.lib.entity.ProjectileMetadata;
|
||||
import io.lumine.mythic.lib.entity.ProjectileType;
|
||||
import net.Indyuce.mmoitems.MMOItems;
|
||||
import net.Indyuce.mmoitems.api.DeathItemsHandler;
|
||||
import net.Indyuce.mmoitems.api.Type;
|
||||
import net.Indyuce.mmoitems.api.interaction.projectile.ArrowPotionEffectArrayItem;
|
||||
import net.Indyuce.mmoitems.api.interaction.util.InteractItem;
|
||||
import net.Indyuce.mmoitems.api.interaction.weapon.Weapon;
|
||||
import net.Indyuce.mmoitems.api.player.PlayerData;
|
||||
import net.Indyuce.mmoitems.api.util.DeathDowngrading;
|
||||
import net.Indyuce.mmoitems.stat.data.PotionEffectData;
|
||||
import net.Indyuce.mmoitems.util.MMOUtils;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.entity.Trident;
|
||||
import org.bukkit.event.EventHandler;
|
||||
@ -24,8 +31,10 @@ import org.bukkit.event.player.PlayerItemHeldEvent;
|
||||
import org.bukkit.event.player.PlayerRespawnEvent;
|
||||
import org.bukkit.event.player.PlayerSwapHandItemsEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.potion.PotionEffectType;
|
||||
import org.bukkit.scheduler.BukkitRunnable;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
@ -119,17 +128,37 @@ public class PlayerListener implements Listener {
|
||||
return;
|
||||
}
|
||||
|
||||
MMOItems.plugin.getEntities().registerCustomProjectile(nbtItem, playerData.getStats().newTemporary(EquipmentSlot.fromBukkit(item.getSlot())), event.getEntity(), 1);
|
||||
final ProjectileMetadata proj = ProjectileMetadata.create(playerData.getStats().newTemporary(EquipmentSlot.fromBukkit(item.getSlot())), ProjectileType.TRIDENT, event.getEntity());
|
||||
proj.setSourceItem(nbtItem);
|
||||
proj.setCustomDamage(true);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(ignoreCancelled = true)
|
||||
public void registerArrowSpecialEffects(PlayerAttackEvent event) {
|
||||
if (!(event.getAttack() instanceof ProjectileAttackMetadata)) return;
|
||||
|
||||
final ProjectileAttackMetadata projAttack = (ProjectileAttackMetadata) event.getAttack();
|
||||
final @Nullable ProjectileMetadata data = ProjectileMetadata.get(projAttack.getProjectile());
|
||||
if (data == null || data.getSourceItem() == null) return;
|
||||
|
||||
// Apply MMOItems-specific effects
|
||||
applyPotionEffects(data, event.getEntity());
|
||||
}
|
||||
|
||||
private void applyPotionEffects(ProjectileMetadata proj, LivingEntity target) {
|
||||
if (proj.getSourceItem().hasTag("MMOITEMS_ARROW_POTION_EFFECTS"))
|
||||
for (ArrowPotionEffectArrayItem entry : MythicLib.plugin.getJson().parse(proj.getSourceItem().getString("MMOITEMS_ARROW_POTION_EFFECTS"), ArrowPotionEffectArrayItem[].class))
|
||||
target.addPotionEffect(new PotionEffectData(PotionEffectType.getByName(entry.type), entry.duration, entry.level).toEffect());
|
||||
}
|
||||
|
||||
/**
|
||||
* Fixes an issue where quickly swapping items in hand just
|
||||
* does not update the player's inventory which can make the
|
||||
* player cast abilities or attacks with not the correct stats
|
||||
*
|
||||
* @deprecated This does cost some performance and that update
|
||||
* method NEEDS some improvement in the future
|
||||
* method NEEDS some improvement in the future
|
||||
*/
|
||||
@Deprecated
|
||||
@EventHandler
|
||||
@ -143,7 +172,7 @@ public class PlayerListener implements Listener {
|
||||
* player cast abilities or attacks with not the correct stats
|
||||
*
|
||||
* @deprecated This does cost some performance and that update
|
||||
* method NEEDS some improvement in the future
|
||||
* method NEEDS some improvement in the future
|
||||
*/
|
||||
@Deprecated
|
||||
@EventHandler
|
||||
|
@ -65,7 +65,6 @@ default-item-capacity:
|
||||
default:
|
||||
attack-speed: 0.67
|
||||
range: 16
|
||||
blunt-rating: 33
|
||||
recoil: 0.1
|
||||
|
||||
# Restart server when changing this option
|
||||
|
@ -31,6 +31,9 @@ SWORD:
|
||||
- '{range}&8- &7Lvl Range: &e#range#'
|
||||
- '{tier}&8- &7Item Tier: #prefix##tier#'
|
||||
|
||||
# What the item type does
|
||||
on-attack: slashing_attack_effect
|
||||
|
||||
DAGGER:
|
||||
display: STONE_SWORD
|
||||
name: 'Dagger'
|
||||
@ -44,6 +47,8 @@ DAGGER:
|
||||
- '{range}&8- &7Lvl Range: &e#range#'
|
||||
- '{tier}&8- &7Item Tier: #prefix##tier#'
|
||||
|
||||
on-attack: piercing_attack_effect
|
||||
|
||||
SPEAR:
|
||||
display: TRIDENT
|
||||
name: 'Spear'
|
||||
@ -57,6 +62,8 @@ SPEAR:
|
||||
- '{range}&8- &7Lvl Range: &e#range#'
|
||||
- '{tier}&8- &7Item Tier: #prefix##tier#'
|
||||
|
||||
on-attack: piercing_attack_effect
|
||||
|
||||
HAMMER:
|
||||
display: IRON_AXE
|
||||
name: 'Hammer'
|
||||
@ -70,8 +77,10 @@ HAMMER:
|
||||
- '{range}&8- &7Lvl Range: &e#range#'
|
||||
- '{tier}&8- &7Item Tier: #prefix##tier#'
|
||||
|
||||
on-attack: blunt_attack_effect
|
||||
|
||||
GAUNTLET:
|
||||
display: IRON_HORSE_ARMOR
|
||||
display: IRON_SHOVEL
|
||||
name: 'Gauntlet'
|
||||
unident-item:
|
||||
name: '&f#prefix#Unidentified Gauntlet'
|
||||
@ -83,6 +92,9 @@ GAUNTLET:
|
||||
- '{range}&8- &7Lvl Range: &e#range#'
|
||||
- '{tier}&8- &7Item Tier: #prefix##tier#'
|
||||
|
||||
on-attack: blunt_attack_effect
|
||||
on-entity-interact: gauntlet_special_attack
|
||||
|
||||
WHIP:
|
||||
display: LEAD
|
||||
name: 'Whip'
|
||||
@ -96,6 +108,10 @@ WHIP:
|
||||
- '{range}&8- &7Lvl Range: &e#range#'
|
||||
- '{tier}&8- &7Item Tier: #prefix##tier#'
|
||||
|
||||
disable-melee-attacks: true
|
||||
on-left-click: whip_attack
|
||||
on-attack: slashing_attack_effect
|
||||
|
||||
STAFF:
|
||||
display: DIAMOND_HOE
|
||||
name: 'Staff'
|
||||
@ -109,6 +125,11 @@ STAFF:
|
||||
- '{range}&8- &7Lvl Range: &e#range#'
|
||||
- '{tier}&8- &7Item Tier: #prefix##tier#'
|
||||
|
||||
disable-melee-attacks: true
|
||||
on-left-click: staff_default
|
||||
attack-cooldown-key: "staff"
|
||||
on-entity-interact: staff_special_attack # Special action when right-clicking entities
|
||||
|
||||
BOW:
|
||||
display: BOW
|
||||
name: 'Bow'
|
||||
@ -122,6 +143,8 @@ BOW:
|
||||
- '{range}&8- &7Lvl Range: &e#range#'
|
||||
- '{tier}&8- &7Item Tier: #prefix##tier#'
|
||||
|
||||
disable-melee-attacks: true
|
||||
|
||||
CROSSBOW:
|
||||
display: WOODEN_PICKAXE
|
||||
name: 'Crossbow'
|
||||
@ -134,6 +157,9 @@ CROSSBOW:
|
||||
- '{tier}&8Item Info:'
|
||||
- '{range}&8- &7Lvl Range: &e#range#'
|
||||
- '{tier}&8- &7Item Tier: #prefix##tier#'
|
||||
|
||||
disable-melee-attacks: true
|
||||
on-right-click: crossbow_attack
|
||||
|
||||
MUSKET:
|
||||
display: IRON_HORSE_ARMOR
|
||||
@ -147,6 +173,10 @@ MUSKET:
|
||||
- '{tier}&8Item Info:'
|
||||
- '{range}&8- &7Lvl Range: &e#range#'
|
||||
- '{tier}&8- &7Item Tier: #prefix##tier#'
|
||||
|
||||
disable-melee-attacks: true
|
||||
# Lutes and muskets attack effects are hardcoded as
|
||||
# of MI 6.10 and cannot be modified at the moment.
|
||||
|
||||
LUTE:
|
||||
display: NAME_TAG
|
||||
@ -160,6 +190,10 @@ LUTE:
|
||||
- '{tier}&8Item Info:'
|
||||
- '{range}&8- &7Lvl Range: &e#range#'
|
||||
- '{tier}&8- &7Item Tier: #prefix##tier#'
|
||||
|
||||
disable-melee-attacks: true
|
||||
# Lutes and muskets attack effects are hardcoded as
|
||||
# of MI 6.10 and cannot be modified at the moment.
|
||||
|
||||
# Applies stats in both hands
|
||||
CATALYST:
|
||||
@ -320,7 +354,6 @@ BLOCK:
|
||||
- '{range}&8- &7Lvl Range: &e#range#'
|
||||
- '{tier}&8- &7Item Tier: #prefix##tier#'
|
||||
|
||||
|
||||
# Default subtypes
|
||||
GREATSWORD:
|
||||
display: DIAMOND_SWORD
|
||||
@ -335,6 +368,8 @@ GREATSWORD:
|
||||
- '{tier}&8Item Info:'
|
||||
- '{range}&8- &7Lvl Range: &e#range#'
|
||||
- '{tier}&8- &7Item Tier: #prefix##tier#'
|
||||
|
||||
on-attack: slashing_attack_effect
|
||||
|
||||
LONG_SWORD:
|
||||
display: STONE_SWORD
|
||||
@ -349,6 +384,8 @@ LONG_SWORD:
|
||||
- '{tier}&8Item Info:'
|
||||
- '{range}&8- &7Lvl Range: &e#range#'
|
||||
- '{tier}&8- &7Item Tier: #prefix##tier#'
|
||||
|
||||
on-attack: slashing_attack_effect
|
||||
|
||||
KATANA:
|
||||
display: IRON_SWORD
|
||||
@ -363,6 +400,8 @@ KATANA:
|
||||
- '{tier}&8Item Info:'
|
||||
- '{range}&8- &7Lvl Range: &e#range#'
|
||||
- '{tier}&8- &7Item Tier: #prefix##tier#'
|
||||
|
||||
on-attack: slashing_attack_effect
|
||||
|
||||
THRUSTING_SWORD:
|
||||
display: GOLDEN_SWORD
|
||||
@ -378,6 +417,8 @@ THRUSTING_SWORD:
|
||||
- '{range}&8- &7Lvl Range: &e#range#'
|
||||
- '{tier}&8- &7Item Tier: #prefix##tier#'
|
||||
|
||||
on-attack: piercing_attack_effect
|
||||
|
||||
AXE:
|
||||
display: STONE_AXE
|
||||
name: 'Axe'
|
||||
@ -392,6 +433,8 @@ AXE:
|
||||
- '{range}&8- &7Lvl Range: &e#range#'
|
||||
- '{tier}&8- &7Item Tier: #prefix##tier#'
|
||||
|
||||
on-attack: slashing_attack_effect
|
||||
|
||||
GREATAXE:
|
||||
display: DIAMOND_AXE
|
||||
name: 'Greataxe'
|
||||
@ -406,6 +449,8 @@ GREATAXE:
|
||||
- '{range}&8- &7Lvl Range: &e#range#'
|
||||
- '{tier}&8- &7Item Tier: #prefix##tier#'
|
||||
|
||||
on-attack: slashing_attack_effect
|
||||
|
||||
HALBERD:
|
||||
display: IRON_AXE
|
||||
name: 'Halberd'
|
||||
@ -420,6 +465,8 @@ HALBERD:
|
||||
- '{range}&8- &7Lvl Range: &e#range#'
|
||||
- '{tier}&8- &7Item Tier: #prefix##tier#'
|
||||
|
||||
on-attack: blunt_attack_effect
|
||||
|
||||
LANCE:
|
||||
display: STICK
|
||||
name: 'Lance'
|
||||
@ -434,6 +481,8 @@ LANCE:
|
||||
- '{range}&8- &7Lvl Range: &e#range#'
|
||||
- '{tier}&8- &7Item Tier: #prefix##tier#'
|
||||
|
||||
on-attack: piercing_attack_effect
|
||||
|
||||
GREATHAMMER:
|
||||
display: DIAMOND_AXE
|
||||
name: 'Greathammer'
|
||||
@ -448,6 +497,8 @@ GREATHAMMER:
|
||||
- '{range}&8- &7Lvl Range: &e#range#'
|
||||
- '{tier}&8- &7Item Tier: #prefix##tier#'
|
||||
|
||||
on-attack: blunt_attack_effect
|
||||
|
||||
GREATSTAFF:
|
||||
display: DIAMOND_HOE
|
||||
name: 'Greatstaff'
|
||||
@ -462,6 +513,8 @@ GREATSTAFF:
|
||||
- '{range}&8- &7Lvl Range: &e#range#'
|
||||
- '{tier}&8- &7Item Tier: #prefix##tier#'
|
||||
|
||||
on-attack: blunt_attack_effect
|
||||
|
||||
STAVE:
|
||||
display: IRON_HOE
|
||||
name: 'Stave'
|
||||
@ -476,6 +529,8 @@ STAVE:
|
||||
- '{range}&8- &7Lvl Range: &e#range#'
|
||||
- '{tier}&8- &7Item Tier: #prefix##tier#'
|
||||
|
||||
on-attack: blunt_attack_effect
|
||||
|
||||
TOME:
|
||||
display: BOOK
|
||||
name: 'Tome'
|
||||
@ -518,6 +573,11 @@ WAND:
|
||||
- '{range}&8- &7Lvl Range: &e#range#'
|
||||
- '{tier}&8- &7Item Tier: #prefix##tier#'
|
||||
|
||||
disable-melee-attacks: true
|
||||
on-left-click: staff_default
|
||||
attack-cooldown-key: "staff"
|
||||
on-entity-interact: staff_special_attack # Special action when right-clicking entities
|
||||
|
||||
GREATBOW:
|
||||
display: BOW
|
||||
name: 'Greatbow'
|
||||
@ -532,6 +592,8 @@ GREATBOW:
|
||||
- '{range}&8- &7Lvl Range: &e#range#'
|
||||
- '{tier}&8- &7Item Tier: #prefix##tier#'
|
||||
|
||||
disable-melee-attacks: true
|
||||
|
||||
SHIELD:
|
||||
display: SHIELD
|
||||
name: 'Shield'
|
||||
|
@ -1,6 +1,6 @@
|
||||
FIGHTING_GAUNTLETS:
|
||||
base:
|
||||
material: IRON_HORSE_ARMOR
|
||||
material: IRON_SHOVEL
|
||||
lore:
|
||||
- §7Tired of breaking your bones when
|
||||
- §7doing hand-to-hand combat?
|
||||
|
@ -1,11 +1,3 @@
|
||||
staff-spirit:
|
||||
nether-spirit: '&3 &7■ Nether Spirit'
|
||||
void-spirit: '&3 &7■ Void Spirit'
|
||||
mana-spirit: '&3 &7■ Mana Spirit'
|
||||
lightning-spirit: '&3 &7■ Lightning Spirit'
|
||||
xray-spirit: '&3 &7■ X-Ray Spirit'
|
||||
thunder-spirit: '&3 &7■ Thunder Spirit'
|
||||
sunfire-spirit: '&3 &7■ Sunfire Spirit'
|
||||
lute-attack:
|
||||
wave: '&3 &7■ Wave Melody'
|
||||
circular: '&3 &7■ Circular Melody'
|
||||
|
@ -82,7 +82,6 @@ lore-format:
|
||||
- '#mana-regeneration#'
|
||||
- '#stamina-regeneration#'
|
||||
- '#movement-speed#'
|
||||
- '#staff-spirit#'
|
||||
- '#lute-attack-effect#'
|
||||
- '#two-handed#'
|
||||
- '#handworn#'
|
||||
|
Loading…
Reference in New Issue
Block a user