Added more effects and started fixing bugs.

This commit is contained in:
GB6 2019-01-30 11:58:37 +01:00
parent 015a8d6ce2
commit eac363e23f
44 changed files with 617 additions and 199 deletions

View File

@ -285,13 +285,12 @@ public class Locale {
* Get a message set for a specific node and replace its params with a supplied arguments.
*
* @param node the node to get
* @param args the replacement arguments
* @return the message for the specified node
*/
public String getMessage(String node, Placeholder... placeholders) {
String message = getMessage(node);
for (Placeholder placeholder : placeholders) {
message = message.replaceAll(placeholder.getPlaceholder(), placeholder.getToReplace().toString());
message = message.replace(placeholder.getPlaceholder(), placeholder.getToReplace().toString());
}
return message;
}

View File

@ -14,7 +14,9 @@ import org.bukkit.inventory.ItemStack;
import java.io.File;
import static com.songoda.epicenchants.enums.EnchantResult.BROKEN_FAILURE;
import static com.songoda.epicenchants.objects.Placeholder.of;
import static com.songoda.epicenchants.utils.GeneralUtils.getMessageFromResult;
@CommandAlias("epicenchants|ee")
public class EnchantCommand extends BaseCommand {
@ -36,7 +38,7 @@ public class EnchantCommand extends BaseCommand {
@CommandPermission("epicenchants.give")
public void onGiveBook(CommandSender sender, @Flags("other") Player target, Enchant enchant, @Optional Integer level, @Optional Integer successRate, @Optional Integer destroyRate) {
target.getInventory().addItem(enchant.getBookItem().get(enchant, level, successRate, destroyRate));
target.sendMessage(instance.getLocale().getMessageWithPrefix("command.book.given", of("enchant", enchant.getIdentifier())));
target.sendMessage(instance.getLocale().getMessageWithPrefix("command.book.received", of("enchant", enchant.getIdentifier())));
sender.sendMessage(instance.getLocale().getMessageWithPrefix("command.book.gave", of("player", target.getName()), of("enchant", enchant.getIdentifier())));
}
@ -50,24 +52,14 @@ public class EnchantCommand extends BaseCommand {
ItemStack before = player.getItemInHand();
Pair<ItemStack, EnchantResult> result = instance.getEnchantUtils().apply(before, enchant, level,
successRate == null ? 100 : successRate, destroyRate == null ? 0 : destroyRate);
String messageKey = "";
switch (result.getRight()) {
case FAILURE:
messageKey = "enchant.failure";
break;
case BROKEN_FAILURE:
player.getInventory().clear(slot);
messageKey = "enchant.brokenfailure";
break;
case SUCCESS:
messageKey = "enchant.success";
break;
case CONFLICT:
messageKey = "enchant.conflict";
player.sendMessage(instance.getLocale().getMessageWithPrefix(getMessageFromResult(result.getRight()), of("enchant", enchant.getIdentifier())));
if (result.getRight() == BROKEN_FAILURE) {
player.getInventory().clear(slot);
return;
}
player.sendMessage(instance.getLocale().getMessageWithPrefix(messageKey, of("enchant", enchant.getIdentifier())));
player.getInventory().setItem(slot, result.getLeft());
}
@ -84,6 +76,7 @@ public class EnchantCommand extends BaseCommand {
@CommandAlias("load")
@Description("Reload all config files, or reload/load specific enchant files")
@CommandCompletion("@enchantFiles")
@CommandPermission("epicenchants.reload")
public void onReload(CommandSender sender, @Optional File fileName) {
if (fileName == null) {
instance.reload();

View File

@ -2,18 +2,20 @@ package com.songoda.epicenchants.effect;
import com.songoda.epicenchants.enums.EventType;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.bukkit.event.Event;
import org.jetbrains.annotations.NotNull;
public abstract class EffectEventExecutor extends EffectExecutor {
public EffectEventExecutor(ConfigurationSection section) {
super(section);
}
public abstract void execute(Player wearer, Player opponent, int level, Event event, EventType eventType);
public abstract void execute(Player wearer, LivingEntity opponent, int level, Event event, EventType eventType);
@Override
public void execute(Player wearer, Player opponent, int level, EventType eventType) {
public void execute(@NotNull Player wearer, LivingEntity opponent, int level, EventType eventType) {
throw new UnsupportedOperationException("This method can not be called on EventEffects");
}
}

View File

@ -6,9 +6,13 @@ import com.songoda.epicenchants.objects.LeveledModifier;
import com.songoda.epicenchants.utils.GeneralUtils;
import lombok.Getter;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.bukkit.event.Event;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Arrays;
import java.util.function.Consumer;
import static com.songoda.epicenchants.effect.EffectExecutor.Who.OPPONENT;
@ -17,17 +21,23 @@ import static com.songoda.epicenchants.effect.EffectExecutor.Who.WEARER;
public abstract class EffectExecutor {
@Getter private final ConfigurationSection section;
@Getter private final EffectType effectType;
private EffectType[] allowedEffects;
public EffectExecutor(ConfigurationSection section) {
public EffectExecutor(ConfigurationSection section, EffectType... allowedEffects) {
this.section = section;
this.effectType = EffectType.valueOf(section.getString("type"));
this.allowedEffects = allowedEffects;
}
public void testAndRun(Player wearer, Player opponent, int level, EffectType type, Event event, EventType eventType) {
public void testAndRun(@NotNull Player wearer, @Nullable LivingEntity opponent, int level, EffectType type, Event event, EventType eventType) {
if (type != effectType) {
return;
}
if (allowedEffects.length != 0 && Arrays.stream(allowedEffects).noneMatch(t -> t == effectType)) {
throw new IllegalStateException(section.getName() + " cannot be triggered by " + effectType.toString());
}
if (section.isString("chance") && !GeneralUtils.chance(LeveledModifier.of(section.getString("chance")).get(level, 100))) {
return;
}
@ -40,7 +50,7 @@ public abstract class EffectExecutor {
execute(wearer, opponent, level, eventType);
}
public abstract void execute(Player wearer, Player opponent, int level, EventType eventType);
public abstract void execute(@NotNull Player wearer, @Nullable LivingEntity opponent, int level, EventType eventType);
public Who who() {
if (section.isString("who")) {
@ -54,7 +64,7 @@ public abstract class EffectExecutor {
return LeveledModifier.of(section.getString("amount"));
}
public void consume(Consumer<Player> playerConsumer, Player wearer, Player opponent) {
public void consume(Consumer<LivingEntity> playerConsumer, Player wearer, @Nullable LivingEntity opponent) {
if (effectType == EffectType.HELD_ITEM || effectType == EffectType.STATIC_EFFECT) {
playerConsumer.accept(wearer);
return;

View File

@ -1,5 +1,6 @@
package com.songoda.epicenchants.effect;
import org.bukkit.Bukkit;
import org.bukkit.configuration.ConfigurationSection;
import java.lang.reflect.Constructor;
@ -23,7 +24,7 @@ public class EffectManager {
Object object = constructor.newInstance(section);
return Optional.of((EffectExecutor) object);
} catch (ClassNotFoundException | NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException | ClassCastException e) {
e.printStackTrace();
Bukkit.getLogger().severe("Invalid effect:" + section.getName());
}
return Optional.empty();

View File

@ -0,0 +1,21 @@
package com.songoda.epicenchants.effect.effects;
import com.songoda.epicenchants.effect.EffectExecutor;
import com.songoda.epicenchants.enums.EventType;
import com.songoda.epicenchants.objects.LeveledModifier;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class Burn extends EffectExecutor {
public Burn(ConfigurationSection section) {
super(section);
}
@Override
public void execute(@NotNull Player wearer, @Nullable LivingEntity opponent, int level, EventType eventType) {
consume(entity -> entity.setFireTicks((int) LeveledModifier.of(getSection().getString("time")).get(level, 20)), wearer, opponent);
}
}

View File

@ -3,6 +3,7 @@ package com.songoda.epicenchants.effect.effects;
import com.songoda.epicenchants.effect.EffectEventExecutor;
import com.songoda.epicenchants.enums.EventType;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.bukkit.event.Cancellable;
import org.bukkit.event.Event;
@ -13,7 +14,7 @@ public class CancelEvent extends EffectEventExecutor {
}
@Override
public void execute(Player player, Player opponent, int level, Event event, EventType eventType) {
public void execute(Player player, LivingEntity opponent, int level, Event event, EventType eventType) {
if (!(event instanceof Cancellable)) {
return;
}

View File

@ -4,7 +4,9 @@ import com.songoda.epicenchants.effect.EffectExecutor;
import com.songoda.epicenchants.enums.EventType;
import org.bukkit.Bukkit;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
public class ConsoleCommand extends EffectExecutor {
public ConsoleCommand(ConfigurationSection section) {
@ -12,10 +14,10 @@ public class ConsoleCommand extends EffectExecutor {
}
@Override
public void execute(Player wearer, Player opponent, int level, EventType eventType) {
Bukkit.getConsoleSender().sendMessage(getSection().getString("command")
public void execute(@NotNull Player wearer, LivingEntity opponent, int level, EventType eventType) {
Bukkit.dispatchCommand(Bukkit.getConsoleSender(), getSection().getString("command")
.replace("{level}", "" + level)
.replace("{wearer}", wearer.getName()
.replace("{opponent}", opponent.getName())));
.replace("{wearer}", wearer.getName())
.replace("{opponent}", opponent == null ? "" : opponent.getName()));
}
}

View File

@ -2,10 +2,16 @@ package com.songoda.epicenchants.effect.effects;
import com.songoda.epicenchants.effect.EffectExecutor;
import com.songoda.epicenchants.enums.EventType;
import com.songoda.epicenchants.utils.ItemBuilder;
import org.bukkit.Material;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.entity.Entity;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.SkullMeta;
import org.jetbrains.annotations.NotNull;
import java.util.Optional;
public class DropHead extends EffectExecutor {
public DropHead(ConfigurationSection section) {
@ -13,8 +19,73 @@ public class DropHead extends EffectExecutor {
}
@Override
public void execute(Player wearer, Player opponent, int level, EventType eventType) {
consume(player -> player.getWorld().dropItemNaturally(player.getLocation(),
new ItemBuilder(Material.LEGACY_SKULL_ITEM).skullOwner(player.getName()).build()), wearer, opponent);
public void execute(@NotNull Player wearer, LivingEntity opponent, int level, EventType eventType) {
consume(entity -> getHead(entity).ifPresent(head -> entity.getWorld().dropItemNaturally(entity.getLocation(), head)), wearer, opponent);
}
private Optional<ItemStack> getHead(Entity entity) {
short data = 3;
String skin = "";
switch (entity.getType()) {
case CHICKEN:
skin = "MHF_Chicken";
break;
case PIG_ZOMBIE:
skin = "MHF_PigZombie";
break;
case PIG:
skin = "MHF_Pig";
break;
case COW:
skin = "MHF_Cow";
break;
case SHEEP:
skin = "MHF_Sheep";
break;
case MUSHROOM_COW:
skin = "MHF_MushroomCow";
break;
case SPIDER:
skin = "MHF_Spider";
break;
case ZOMBIE:
data = 2;
break;
case SKELETON:
data = 0;
break;
case VILLAGER:
skin = "MHF_Villager";
break;
case MAGMA_CUBE:
skin = "MHF_LavaSlime";
break;
case BLAZE:
skin = "MHF_Blaze";
break;
case CREEPER:
data = 4;
case ENDERMAN:
skin = "MHF_Enderman";
break;
case RABBIT:
skin = "MHF_Rabbit";
break;
case IRON_GOLEM:
skin = "MHF_Golem";
case PLAYER:
break;
default:
return Optional.empty();
}
ItemStack out = new ItemStack(Material.LEGACY_SKULL_ITEM, 1, data);
SkullMeta skullMeta = (SkullMeta) out.getItemMeta();
skullMeta.setOwner(entity instanceof Player ? entity.getName() : skin);
out.setItemMeta(skullMeta);
return Optional.of(out);
}
}

View File

@ -3,7 +3,9 @@ package com.songoda.epicenchants.effect.effects;
import com.songoda.epicenchants.effect.EffectExecutor;
import com.songoda.epicenchants.enums.EventType;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
public class Extinguish extends EffectExecutor {
public Extinguish(ConfigurationSection section) {
@ -11,7 +13,7 @@ public class Extinguish extends EffectExecutor {
}
@Override
public void execute(Player wearer, Player opponent, int level, EventType eventType) {
public void execute(@NotNull Player wearer, LivingEntity opponent, int level, EventType eventType) {
consume(player -> player.setFireTicks(0), wearer, opponent);
}
}

View File

@ -1,24 +1,23 @@
package com.songoda.epicenchants.effect.effects;
import com.songoda.epicenchants.effect.EffectExecutor;
import com.songoda.epicenchants.enums.EffectType;
import com.songoda.epicenchants.enums.EventType;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import static com.songoda.epicenchants.enums.EffectType.HELD_ITEM;
import static com.songoda.epicenchants.enums.EffectType.STATIC_EFFECT;
import static com.songoda.epicenchants.enums.EventType.ON;
public class Fly extends EffectExecutor {
public Fly(ConfigurationSection section) {
super(section);
super(section, STATIC_EFFECT, HELD_ITEM);
}
@Override
public void execute(Player wearer, Player opponent, int level, EventType eventType) {
if (this.getEffectType() != EffectType.STATIC_EFFECT && this.getEffectType() != EffectType.HELD_ITEM) {
throw new IllegalStateException("Fly effect is not a STATIC_EFFECT or HELD_ITEM");
}
public void execute(@NotNull Player wearer, LivingEntity opponent, int level, EventType eventType) {
wearer.setAllowFlight(eventType == ON);
wearer.setFlying(eventType == ON);
}

View File

@ -3,7 +3,9 @@ package com.songoda.epicenchants.effect.effects;
import com.songoda.epicenchants.effect.EffectExecutor;
import com.songoda.epicenchants.enums.EventType;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
public class Lightning extends EffectExecutor {
public Lightning(ConfigurationSection section) {
@ -11,7 +13,7 @@ public class Lightning extends EffectExecutor {
}
@Override
public void execute(Player wearer, Player opponent, int level, EventType eventType) {
consume(player -> player.getWorld().strikeLightning(player.getLocation()), wearer, opponent);
public void execute(@NotNull Player wearer, LivingEntity opponent, int level, EventType eventType) {
consume(entity -> entity.getWorld().strikeLightning(entity.getLocation()), wearer, opponent);
}
}

View File

@ -3,7 +3,9 @@ package com.songoda.epicenchants.effect.effects;
import com.songoda.epicenchants.effect.EffectExecutor;
import com.songoda.epicenchants.enums.EventType;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import static com.songoda.epicenchants.utils.GeneralUtils.color;
@ -13,9 +15,9 @@ public class Message extends EffectExecutor {
}
@Override
public void execute(Player wearer, Player opponent, int level, EventType eventType) {
public void execute(@NotNull Player wearer, LivingEntity opponent, int level, EventType eventType) {
if (eventType == EventType.ON || eventType == EventType.NONE)
consume(player -> player.sendMessage(color(getSection().getString("message"))
consume(entity -> entity.sendMessage(color(getSection().getString("message"))
.replace("{level}", "" + level)
.replace("{wearer}", wearer.getName())
.replace("{opponent}", opponent.getName())), wearer, opponent);

View File

@ -4,6 +4,7 @@ import com.songoda.epicenchants.effect.EffectEventExecutor;
import com.songoda.epicenchants.enums.EventType;
import com.songoda.epicenchants.objects.LeveledModifier;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.bukkit.event.Event;
import org.bukkit.event.entity.EntityDamageEvent;
@ -14,7 +15,7 @@ public class ModifyDamage extends EffectEventExecutor {
}
@Override
public void execute(Player wearer, Player opponent, int level, Event event, EventType eventType) {
public void execute(Player wearer, LivingEntity opponent, int level, Event event, EventType eventType) {
if (!(event instanceof EntityDamageEvent)) {
return;
}

View File

@ -0,0 +1,26 @@
package com.songoda.epicenchants.effect.effects;
import com.songoda.epicenchants.effect.EffectExecutor;
import com.songoda.epicenchants.enums.EffectType;
import com.songoda.epicenchants.enums.EventType;
import com.songoda.epicenchants.utils.Experience;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class ModifyExp extends EffectExecutor {
public ModifyExp(ConfigurationSection section, EffectType... allowedEffects) {
super(section, allowedEffects);
}
@Override
public void execute(@NotNull Player wearer, @Nullable LivingEntity opponent, int level, EventType eventType) {
consume(entity -> {
if (entity instanceof Player) {
Experience.changeExp(((Player) entity), (int) getAmount().get(level, 0));
}
}, wearer, opponent);
}
}

View File

@ -0,0 +1,25 @@
package com.songoda.epicenchants.effect.effects;
import com.songoda.epicenchants.effect.EffectExecutor;
import com.songoda.epicenchants.enums.EffectType;
import com.songoda.epicenchants.enums.EventType;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class ModifyFood extends EffectExecutor {
public ModifyFood(ConfigurationSection section, EffectType... allowedEffects) {
super(section, allowedEffects);
}
@Override
public void execute(@NotNull Player wearer, @Nullable LivingEntity opponent, int level, EventType eventType) {
consume(entity -> {
if (entity instanceof Player) {
((Player) entity).setFoodLevel((int) (((Player) entity).getFoodLevel() + getAmount().get(level, 0)));
}
}, wearer, opponent);
}
}

View File

@ -0,0 +1,27 @@
package com.songoda.epicenchants.effect.effects;
import com.songoda.epicenchants.effect.EffectExecutor;
import com.songoda.epicenchants.enums.EventType;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
public class ModifyHealth extends EffectExecutor {
public ModifyHealth(ConfigurationSection section) {
super(section);
}
@Override
public void execute(@NotNull Player wearer, LivingEntity opponent, int level, EventType eventType) {
consume(entity -> {
double amount = getAmount().get(level, 0);
if (entity.getHealth() + amount > entity.getMaxHealth()) {
entity.setHealth(entity.getMaxHealth());
} else {
entity.setHealth(entity.getHealth() + amount);
}
}, wearer, opponent);
}
}

View File

@ -4,6 +4,7 @@ import com.songoda.epicenchants.effect.EffectEventExecutor;
import com.songoda.epicenchants.enums.EventType;
import com.songoda.epicenchants.objects.LeveledModifier;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.bukkit.event.Event;
import org.bukkit.event.entity.EntityDeathEvent;
@ -18,7 +19,7 @@ public class MoreDrops extends EffectEventExecutor {
}
@Override
public void execute(Player player, Player opponent, int level, Event event, EventType type) {
public void execute(Player player, LivingEntity opponent, int level, Event event, EventType type) {
if (!(event instanceof EntityDeathEvent)) {
return;
}

View File

@ -3,8 +3,11 @@ package com.songoda.epicenchants.effect.effects;
import com.songoda.epicenchants.effect.EffectExecutor;
import com.songoda.epicenchants.enums.EventType;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import static com.songoda.epicenchants.effect.EffectExecutor.Who.OPPONENT;
import static com.songoda.epicenchants.enums.EventType.NONE;
import static com.songoda.epicenchants.enums.EventType.ON;
@ -14,12 +17,17 @@ public class PlayerCommand extends EffectExecutor {
}
@Override
public void execute(Player wearer, Player opponent, int level, EventType eventType) {
if (eventType == ON || eventType == NONE)
consume(player -> player.performCommand(getSection().getString("command")
public void execute(@NotNull Player wearer, LivingEntity opponent, int level, EventType eventType) {
if (eventType == ON || eventType == NONE) {
if (who() == OPPONENT && !(opponent instanceof Player)) {
return;
}
consume(entity -> ((Player) entity).performCommand(getSection().getString("command")
.replace("{level}", "" + level)
.replace("{wearer}", wearer.getName())
.replace("{opponent}", opponent.getName())), wearer, opponent);
}
}
}

View File

@ -4,11 +4,12 @@ import com.songoda.epicenchants.effect.EffectExecutor;
import com.songoda.epicenchants.enums.EffectType;
import com.songoda.epicenchants.enums.EventType;
import com.songoda.epicenchants.objects.LeveledModifier;
import com.songoda.epicenchants.utils.GeneralUtils;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;
import org.jetbrains.annotations.NotNull;
public class Potion extends EffectExecutor {
public Potion(ConfigurationSection section) {
@ -16,7 +17,7 @@ public class Potion extends EffectExecutor {
}
@Override
public void execute(Player wearer, Player opponent, int level, EventType eventType) {
public void execute(@NotNull Player wearer, LivingEntity opponent, int level, EventType eventType) {
if (!getSection().isString("potion-type")) {
return;
}
@ -28,24 +29,19 @@ public class Potion extends EffectExecutor {
return;
}
if (this.getEffectType() == EffectType.STATIC_EFFECT || this.getEffectType() == EffectType.HELD_ITEM) {
if (getEffectType() == EffectType.STATIC_EFFECT || getEffectType() == EffectType.HELD_ITEM) {
if (eventType == EventType.ON) {
consume(player -> player.addPotionEffect(new PotionEffect(effectType, Integer.MAX_VALUE, ((int) amplifier.get(level, 0)),
consume(entity -> entity.addPotionEffect(new PotionEffect(effectType, Integer.MAX_VALUE, ((int) amplifier.get(level, 0)),
false, false)), wearer, opponent);
} else if (eventType == EventType.OFF) {
consume(player -> player.removePotionEffect(effectType), wearer, opponent);
consume(entity -> entity.removePotionEffect(effectType), wearer, opponent);
}
return;
}
LeveledModifier duration = LeveledModifier.of(getSection().getString("duration"));
LeveledModifier chance = LeveledModifier.of(getSection().getString("chance"));
if (!GeneralUtils.chance(chance.get(level, 100))) {
return;
}
consume(player -> player.addPotionEffect(new PotionEffect(effectType, ((int) duration.get(level, Integer.MAX_VALUE)),
consume(entity -> entity.addPotionEffect(new PotionEffect(effectType, ((int) duration.get(level, 60)),
((int) amplifier.get(level, 0)), false, false)), wearer, opponent);
}

View File

@ -0,0 +1,28 @@
package com.songoda.epicenchants.effect.effects;
import com.songoda.epicenchants.effect.EffectExecutor;
import com.songoda.epicenchants.enums.EventType;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class RemoveEffect extends EffectExecutor {
public RemoveEffect(ConfigurationSection section) {
super(section);
}
@Override
public void execute(@NotNull Player wearer, @Nullable LivingEntity opponent, int level, EventType eventType) {
consume(entity -> {
if (!getSection().isString("potion-type")) {
entity.getActivePotionEffects().stream().map(PotionEffect::getType).forEach(entity::removePotionEffect);
} else {
entity.removePotionEffect(PotionEffectType.getByName(getSection().getString("potion-type")));
}
}, wearer, opponent);
}
}

View File

@ -3,7 +3,9 @@ package com.songoda.epicenchants.effect.effects;
import com.songoda.epicenchants.effect.EffectExecutor;
import com.songoda.epicenchants.enums.EventType;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
public class Repair extends EffectExecutor {
public Repair(ConfigurationSection section) {
@ -11,7 +13,10 @@ public class Repair extends EffectExecutor {
}
@Override
public void execute(Player wearer, Player opponent, int level, EventType eventType) {
consume(player -> player.getItemInHand().setDurability((short) 0), wearer, opponent);
public void execute(@NotNull Player wearer, LivingEntity opponent, int level, EventType eventType) {
consume(livingEntity -> {
if (livingEntity instanceof Player)
((Player) livingEntity).getItemInHand().setDurability((short) 0);
}, wearer, opponent);
}
}

View File

@ -3,7 +3,9 @@ package com.songoda.epicenchants.effect.effects;
import com.songoda.epicenchants.effect.EffectExecutor;
import com.songoda.epicenchants.enums.EventType;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
public class StealHealth extends EffectExecutor {
public StealHealth(ConfigurationSection section) {
@ -11,7 +13,7 @@ public class StealHealth extends EffectExecutor {
}
@Override
public void execute(Player wearer, Player opponent, int level, EventType eventType) {
public void execute(@NotNull Player wearer, LivingEntity opponent, int level, EventType eventType) {
double amount = getAmount().get(level, 0);
wearer.setHealth(wearer.getHealth() + amount);
opponent.setHealth(opponent.getHealth() - amount);

View File

@ -4,8 +4,10 @@ import com.songoda.epicenchants.effect.EffectExecutor;
import com.songoda.epicenchants.enums.EventType;
import com.songoda.epicenchants.objects.LeveledModifier;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.bukkit.util.Vector;
import org.jetbrains.annotations.NotNull;
import static com.songoda.epicenchants.effect.EffectExecutor.Who.WEARER;
@ -15,8 +17,8 @@ public class Throw extends EffectExecutor {
}
@Override
public void execute(Player wearer, Player opponent, int level, EventType eventType) {
if (!getSection().isString("direction") || !getSection().isString("magnitude")) {
public void execute(@NotNull Player wearer, LivingEntity opponent, int level, EventType eventType) {
if (!getSection().isString("direction")) {
return;
}
@ -26,7 +28,7 @@ public class Throw extends EffectExecutor {
Vector vector;
double magnitude = LeveledModifier.of(getSection().getString("magnitude")).get(level, 0.1);
Player player = who() == WEARER ? wearer : opponent;
LivingEntity livingEntity = who() == WEARER ? wearer : opponent;
switch (getSection().getString("direction").toLowerCase()) {
case "up":
@ -36,16 +38,16 @@ public class Throw extends EffectExecutor {
vector = new Vector(0, -magnitude, 0);
break;
case "backward":
vector = player.getLocation().getDirection().multiply(-magnitude);
vector = livingEntity.getLocation().getDirection().multiply(-magnitude);
break;
case "forward":
vector = player.getLocation().getDirection().multiply(magnitude);
vector = livingEntity.getLocation().getDirection().multiply(magnitude);
break;
default:
vector = new Vector();
}
if (vector.length() != 0)
player.setVelocity(vector);
livingEntity.setVelocity(vector);
}
}

View File

@ -4,7 +4,9 @@ import com.songoda.epicenchants.effect.EffectExecutor;
import com.songoda.epicenchants.enums.EventType;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
public class Tnt extends EffectExecutor {
public Tnt(ConfigurationSection section) {
@ -12,7 +14,7 @@ public class Tnt extends EffectExecutor {
}
@Override
public void execute(Player wearer, Player opponent, int level, EventType eventType) {
public void execute(@NotNull Player wearer, LivingEntity opponent, int level, EventType eventType) {
consume(player -> player.getWorld().spawnEntity(player.getLocation(), EntityType.PRIMED_TNT), wearer, opponent);
}
}

View File

@ -1,5 +1,5 @@
package com.songoda.epicenchants.enums;
public enum EnchantResult {
SUCCESS, FAILURE, BROKEN_FAILURE, CONFLICT,
SUCCESS, FAILURE, BROKEN_FAILURE, CONFLICT, MAXED_OUT, ALREADY_APPLIED
}

View File

@ -4,10 +4,10 @@ import com.songoda.epicenchants.EpicEnchants;
import com.songoda.epicenchants.enums.EnchantResult;
import com.songoda.epicenchants.events.EnchantApplyEvent;
import com.songoda.epicenchants.objects.Enchant;
import com.songoda.epicenchants.utils.GeneralUtils;
import de.tr7zw.itemnbtapi.NBTItem;
import org.apache.commons.lang3.tuple.Pair;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
@ -16,6 +16,7 @@ import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.event.inventory.InventoryType;
import org.bukkit.inventory.ItemStack;
import static com.songoda.epicenchants.enums.EnchantResult.*;
import static com.songoda.epicenchants.objects.Placeholder.of;
public class BookListener implements Listener {
@ -58,21 +59,27 @@ public class BookListener implements Listener {
Pair<ItemStack, EnchantResult> result = instance.getEnchantUtils().apply(toApplyTo, enchant, enchantEvent.getLevel(), enchantEvent.getSuccessRate(), enchantEvent.getDestroyRate());
switch (result.getRight()) {
case FAILURE:
event.getWhoClicked().sendMessage(instance.getLocale().getMessageWithPrefix("enchant.failure", of("enchant", enchant.getIdentifier())));
break;
case BROKEN_FAILURE:
event.getCurrentItem().setType(Material.AIR);
event.getWhoClicked().sendMessage(instance.getLocale().getMessageWithPrefix("enchant.brokenfailure", of("enchant", enchant.getIdentifier())));
break;
case SUCCESS:
event.getWhoClicked().sendMessage(instance.getLocale().getMessageWithPrefix("enchant.success", of("enchant", enchant.getIdentifier())));
event.getWhoClicked().sendMessage(instance.getLocale().getMessageWithPrefix(GeneralUtils.getMessageFromResult(result.getRight()),
of("enchant", enchant.getIdentifier())));
event.setCancelled(true);
if (result.getRight() == BROKEN_FAILURE) {
event.getClickedInventory().clear(event.getSlot());
return;
}
if (result.getRight() != CONFLICT && result.getRight() != MAXED_OUT) {
if (event.getCursor().getAmount() > 1) {
ItemStack toSet = event.getCursor();
toSet.setAmount(toSet.getAmount() - 1);
event.getWhoClicked().setItemOnCursor(toSet);
} else {
event.getWhoClicked().setItemOnCursor(null);
}
}
event.getWhoClicked().setItemOnCursor(null);
event.getClickedInventory().setItem(event.getSlot(), result.getLeft());
event.setCancelled(true);
}
}

View File

@ -2,7 +2,8 @@ package com.songoda.epicenchants.listeners;
import com.songoda.epicenchants.EpicEnchants;
import com.songoda.epicenchants.enums.EffectType;
import org.bukkit.entity.Explosive;
import de.tr7zw.itemnbtapi.NBTEntity;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Monster;
import org.bukkit.entity.Player;
import org.bukkit.entity.Projectile;
@ -16,9 +17,6 @@ import org.bukkit.event.entity.EntityTargetLivingEntityEvent;
import org.bukkit.projectiles.ProjectileSource;
import static com.songoda.epicenchants.enums.EffectType.*;
import static com.songoda.epicenchants.utils.Constants.MONSTER_MAP;
import static org.bukkit.entity.EntityType.PLAYER;
import static org.bukkit.event.entity.EntityDamageEvent.DamageCause.*;
public class EntityListener implements Listener {
private final EpicEnchants instance;
@ -30,44 +28,55 @@ public class EntityListener implements Listener {
@EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST)
public void onEntityDeath(EntityDeathEvent event) {
if (event.getEntity() instanceof Monster && event.getEntity().getKiller() != null) {
instance.getEnchantUtils().handlePlayer(event.getEntity().getKiller(), event, KILLED_MOB);
instance.getEnchantUtils().handlePlayer(event.getEntity().getKiller(), event.getEntity(), event, KILLED_MOB);
}
}
@EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST)
public void onEntityDamageByEntity(EntityDamageByEntityEvent event) {
if (!(event.getEntity() instanceof LivingEntity)) {
return;
}
LivingEntity hitEntity = (LivingEntity) event.getEntity();
//Hit by projectile
if (event.getDamager() instanceof Projectile) {
ProjectileSource source = ((Projectile) event.getDamager()).getShooter();
if (event.getEntity() instanceof Player) {
instance.getEnchantUtils().handlePlayer(((Player) event.getEntity()), event, source instanceof Player ? DEFENSE_PLAYER_RANGE : DEFENSE_MOB_RANGE);
if (hitEntity instanceof Player) {
LivingEntity opponent = source instanceof LivingEntity ? ((LivingEntity) source) : null;
EffectType type = source instanceof Player ? DEFENSE_PLAYER_RANGE : DEFENSE_MOB_RANGE;
instance.getEnchantUtils().handlePlayer(((Player) hitEntity), opponent, event, type);
}
if (!(source instanceof Player)) {
return;
if (source instanceof Player) {
EffectType type = event.getEntity() instanceof Player ? ATTACK_PLAYER_RANGE : ATTACK_MOB_RANGE;
instance.getEnchantUtils().handlePlayer(((Player) source), hitEntity, event, type);
}
instance.getEnchantUtils().handlePlayer(((Player) source), event, event.getEntity() instanceof Player ? ATTACK_PLAYER_RANGE : ATTACK_MOB_RANGE);
}
//Player got hit
if (event.getEntity() instanceof Player) {
Player defender = (Player) event.getEntity();
EffectType effectType = null;
LivingEntity opponent = null;
if (event.getDamager() instanceof Player) {
opponent = ((LivingEntity) event.getDamager());
effectType = DEFENSE_PLAYER_MELEE;
} else if (event.getDamager() instanceof Monster) {
opponent = ((LivingEntity) event.getDamager());
effectType = DEFENSE_MOB_MELEE;
} else if (event.getDamager() instanceof Explosive) {
effectType = EXPLOSION_DAMAGE;
}
if (effectType != null) {
instance.getEnchantUtils().handlePlayer(defender, event, effectType);
instance.getEnchantUtils().handlePlayer(defender, opponent, event, effectType);
}
}
//Player damaged an entity
if (event.getDamager() instanceof Player) {
Player attacker = (Player) event.getDamager();
EffectType effectType = null;
@ -79,10 +88,8 @@ public class EntityListener implements Listener {
}
if (effectType != null) {
instance.getEnchantUtils().handlePlayer(attacker, event, effectType);
instance.getEnchantUtils().handlePlayer(attacker, ((LivingEntity) event.getEntity()), event, effectType);
}
instance.getEnchantUtils().handlePlayer(attacker, event, event.getEntityType() == PLAYER ? ATTACK_PLAYER_MELEE : ATTACK_MOB_MELEE);
}
}
@ -91,19 +98,28 @@ public class EntityListener implements Listener {
if (!(event.getEntity() instanceof Player)) {
return;
}
if (event.getCause() == FALL) {
instance.getEnchantUtils().handlePlayer(((Player) event.getEntity()), event, FALL_DAMAGE);
return;
}
if (event.getCause() == FIRE || event.getCause() == FIRE_TICK) {
instance.getEnchantUtils().handlePlayer(((Player) event.getEntity()), event, FIRE_DAMAGE);
switch (event.getCause()) {
case FALL:
instance.getEnchantUtils().handlePlayer(((Player) event.getEntity()), null, event, FALL_DAMAGE);
break;
case FIRE:
case FIRE_TICK:
instance.getEnchantUtils().handlePlayer(((Player) event.getEntity()), null, event, FIRE_DAMAGE);
break;
case BLOCK_EXPLOSION:
case ENTITY_EXPLOSION:
instance.getEnchantUtils().handlePlayer(((Player) event.getEntity()), null, event, EXPLOSION_DAMAGE);
break;
}
}
@EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST)
public void onEntityTargetLivingEntity(EntityTargetLivingEntityEvent event) {
if (MONSTER_MAP.containsValue(event.getEntity().getUniqueId())) {
if (event.getEntity() == null || event.getTarget() == null) {
return;
}
if (new NBTEntity(event.getEntity()).hasKey(event.getTarget().getUniqueId().toString())) {
//TODO: Add team support.
event.setCancelled(true);
}

View File

@ -11,7 +11,9 @@ import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.event.entity.PlayerDeathEvent;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.event.player.PlayerItemHeldEvent;
import org.bukkit.event.player.PlayerJoinEvent;
import java.util.Arrays;
import java.util.Map;
import static com.songoda.epicenchants.enums.EffectType.*;
@ -46,22 +48,33 @@ public class PlayerListener implements Listener {
@EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST)
public void onPlayerDeath(PlayerDeathEvent event) {
instance.getEnchantUtils().handlePlayer(event.getEntity(), event, DEATH);
instance.getEnchantUtils().handlePlayer(event.getEntity(), event.getEntity().getKiller(), event, DEATH);
if (event.getEntity().getKiller() != null) {
instance.getEnchantUtils().handlePlayer(event.getEntity().getKiller(), event, KILLED_PLAYER);
instance.getEnchantUtils().handlePlayer(event.getEntity().getKiller(), event.getEntity(), event, KILLED_PLAYER);
}
}
@EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST)
@EventHandler(priority = EventPriority.HIGHEST)
public void onPlayerInteract(PlayerInteractEvent event) {
if (event.getAction() == Action.RIGHT_CLICK_AIR || event.getAction() == Action.RIGHT_CLICK_BLOCK) {
instance.getEnchantUtils().handlePlayer(event.getPlayer(), event, RIGHT_CLICK);
instance.getEnchantUtils().handlePlayer(event.getPlayer(), null, event, RIGHT_CLICK);
}
}
@EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST)
public void onBlockBreak(BlockBreakEvent event) {
instance.getEnchantUtils().handlePlayer(event.getPlayer(), event, BLOCK_BREAK);
instance.getEnchantUtils().handlePlayer(event.getPlayer(), null, event, BLOCK_BREAK);
}
@EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST)
public void onPlayerJoin(PlayerJoinEvent event) {
event.getPlayer().getActivePotionEffects().stream().filter(potion -> potion.getDuration() >= 32760)
.forEach(potionEffect -> event.getPlayer().removePotionEffect(potionEffect.getType()));
Arrays.stream(event.getPlayer().getInventory().getArmorContents()).forEach(itemStack -> {
instance.getEnchantUtils().getEnchants(itemStack).forEach((enchant, level) ->
enchant.onAction(event.getPlayer(), null, event, level, STATIC_EFFECT, ON));
});
}
}

View File

@ -12,8 +12,9 @@ import org.bukkit.inventory.ItemStack;
import java.util.Optional;
import static com.songoda.epicenchants.objects.Placeholder.of;
import static com.songoda.epicenchants.utils.Experience.changeExp;
import static com.songoda.epicenchants.utils.Experience.getExp;
import static com.songoda.epicenchants.utils.GeneralUtils.color;
import static com.songoda.epicenchants.utils.GeneralUtils.getSlot;
public class EnchanterMenu extends FastInv {
public EnchanterMenu(EpicEnchants instance, FileConfiguration config, Player player) {
@ -30,18 +31,19 @@ public class EnchanterMenu extends FastInv {
.forEach(section -> {
double expCost = section.getDouble("exp-cost");
double ecoCost = section.getDouble("eco-cost");
double xpLeft = expCost - player.getLevel();
double ecoLeft = ecoCost - instance.getEconomy().getBalance(player);
double xpLeft = expCost - player.getLevel() < 0 ? 0 : expCost - player.getLevel();
double ecoLeft = ecoCost - instance.getEconomy().getBalance(player) < 0 ? 0 : ecoCost - instance.getEconomy().getBalance(player);
Group group = instance.getGroupManager().getGroup(section.getString("group").toUpperCase())
.orElseThrow(() -> new IllegalArgumentException("Invalid group set in enchanter: " + section.getString("group")));
ItemStack itemStack = new ItemBuilder(section,
of("exp_cost", expCost),
of("eco_cost", ecoCost),
of("xp_left", xpLeft),
of("exp_left", xpLeft),
of("eco_left", ecoLeft)).build();
addItem(getSlot(section.getInt("row"), section.getInt("column")), itemStack, event -> {
if (!instance.getEconomy().has((player), ecoCost) || (player).getLevel() < expCost) {
addItem(section.getInt("slot"), itemStack, event -> {
if (!instance.getEconomy().has((player), ecoCost) || getExp(player) < expCost) {
player.sendMessage(instance.getLocale().getPrefix() + instance.getLocale().getMessage("event.purchase.cannotafford"));
return;
}
@ -54,9 +56,9 @@ public class EnchanterMenu extends FastInv {
}
instance.getEconomy().withdrawPlayer(player, ecoCost);
player.setLevel((int) (player.getLevel() - expCost));
changeExp(player, (int) -expCost);
player.getInventory().addItem(enchant.get().getBookItem().get(enchant.get()));
player.sendMessage(instance.getLocale().getMessageWithPrefix("event.purchase.success", of("group_name", group.getName())));
player.sendMessage(instance.getLocale().getMessageWithPrefix("event.purchase.success", of("group-name", group.getName())));
});
});
}

View File

@ -23,7 +23,9 @@ public class BookItem {
}
public ItemStack get(Enchant enchant, int level) {
return get(enchant, level, current().nextInt(101), current().nextInt(101));
return get(enchant, level,
current().nextInt(enchant.getGroup().getSuccessRateMin(), enchant.getGroup().getSuccessRateMax()),
current().nextInt(enchant.getGroup().getDestroyRateMin(), enchant.getGroup().getDestroyRateMax()));
}
public ItemStack get(Enchant enchant, @Optional Integer level, @Optional Integer successRate, @Optional Integer destroyRate) {

View File

@ -7,8 +7,10 @@ import com.songoda.epicenchants.wrappers.MobWrapper;
import lombok.Builder;
import lombok.Getter;
import org.bukkit.Material;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.bukkit.event.Event;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Set;
@ -28,9 +30,9 @@ public class Enchant {
@Nullable private BookItem bookItem;
private LeveledModifier modifyDamage;
public void onAction(Player wearer, Player attacker, Event event, int level, EffectType effectType, EventType eventType) {
effectExecutors.forEach(effect -> effect.testAndRun(wearer, attacker, level, effectType, event, eventType));
mobs.forEach(mobWrapper -> mobWrapper.trySpawn(wearer, attacker, level, effectType));
public void onAction(@NotNull Player wearer, @Nullable LivingEntity opponent, Event event, int level, EffectType effectType, EventType eventType) {
effectExecutors.forEach(effect -> effect.testAndRun(wearer, opponent, level, effectType, event, eventType));
mobs.forEach(mobWrapper -> mobWrapper.trySpawn(wearer, opponent, level, effectType));
}
public BookItem getBookItem() {

View File

@ -12,4 +12,5 @@ public class Group {
private String color;
private int slotsUsed;
private BookItem bookItem;
private int destroyRateMin, destroyRateMax, successRateMin, successRateMax;
}

View File

@ -8,7 +8,7 @@ public class Placeholder {
private Object toReplace;
private Placeholder(String placeholder, Object toReplace) {
this.placeholder = "\\{" + placeholder + "\\}";
this.placeholder = "{" + placeholder + "}";
this.toReplace = toReplace;
}

View File

@ -89,6 +89,10 @@ public class ConfigParser {
.color(section.getString("group-color"))
.bookItem(parseBookItem(section.getConfigurationSection("book-item")))
.slotsUsed(section.getInt("slots-used"))
.destroyRateMin(section.getInt("rates.destroy-min"))
.destroyRateMax(section.getInt("rates.destroy-max"))
.successRateMin(section.getInt("rates.success-min"))
.successRateMax(section.getInt("rates.success-max"))
.build() : null;
}
}

View File

@ -1,10 +0,0 @@
package com.songoda.epicenchants.utils;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Multimap;
import java.util.UUID;
public interface Constants {
Multimap<UUID, UUID> MONSTER_MAP = HashMultimap.create();
}

View File

@ -9,11 +9,13 @@ import de.tr7zw.itemnbtapi.NBTCompound;
import de.tr7zw.itemnbtapi.NBTItem;
import org.apache.commons.lang3.tuple.Pair;
import org.bukkit.Material;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.bukkit.event.Event;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import javax.annotation.Nullable;
import java.util.*;
import java.util.stream.Collectors;
@ -33,10 +35,20 @@ public class EnchantUtils {
return GeneralUtils.chance(destroyRate) ? Pair.of(new ItemStack(Material.AIR), BROKEN_FAILURE) : Pair.of(itemStack, FAILURE);
}
if (getEnchants(itemStack).keySet().stream().anyMatch(s -> enchant.getConflict().contains(s.getIdentifier()))) {
Map<Enchant, Integer> enchantMap = getEnchants(itemStack);
if (enchantMap.keySet().stream().anyMatch(s -> enchant.getConflict().contains(s.getIdentifier()))) {
return Pair.of(itemStack, CONFLICT);
}
if (enchantMap.entrySet().stream().anyMatch(entry -> entry.getKey().equals(enchant) && entry.getValue() == enchant.getMaxLevel())) {
return Pair.of(itemStack, MAXED_OUT);
}
if (enchantMap.entrySet().stream().anyMatch(entry -> entry.getKey().equals(enchant) && entry.getValue() == level)) {
return Pair.of(itemStack, ALREADY_APPLIED);
}
ItemBuilder itemBuilder = new ItemBuilder(itemStack);
itemBuilder.removeLore(enchant.getFormat().replace("{level}", "").trim());
itemBuilder.addLore(enchant.getFormat().replace("{level}", "" + level));
@ -66,11 +78,7 @@ public class EnchantUtils {
.collect(Collectors.toMap(key -> instance.getEnchantManager().getEnchantUnsafe(key), compound::getInteger));
}
public void handlePlayer(Player player, Event event, EffectType effectType) {
if (player == null) {
return;
}
public void handlePlayer(@NotNull Player player, @Nullable LivingEntity opponent, Event event, EffectType effectType) {
List<ItemStack> stacks = new ArrayList<>(Arrays.asList(player.getInventory().getArmorContents()));
stacks.add(player.getItemInHand());
stacks.removeIf(Objects::isNull);
@ -80,10 +88,6 @@ public class EnchantUtils {
}
stacks.stream().map(this::getEnchants).forEach(list -> list.forEach((enchant, level) -> {
Player opponent = event instanceof EntityDamageByEntityEvent ?
((EntityDamageByEntityEvent) event).getDamager() instanceof Player ?
((Player) ((EntityDamageByEntityEvent) event).getDamager()) : null : null;
enchant.onAction(player, opponent, event, level, effectType, EventType.NONE);
}));
}

View File

@ -0,0 +1,103 @@
package com.songoda.epicenchants.utils;
import org.bukkit.entity.Player;
/**
* A utility for managing Player experience properly.
*
* @author Jikoo
*/
public class Experience {
/**
* Calculates a player's total exp based on level and progress to next.
*
* @param player the Player
* @return the amount of exp the Player has
*/
public static int getExp(Player player) {
return getExpFromLevel(player.getLevel())
+ Math.round(getExpToNext(player.getLevel()) * player.getExp());
}
/**
* Calculates total experience based on level.
* <p>
* "One can determine how much experience has been collected to reach a level using the equations:
* <p>
* Total Experience = [Level]2 + 6[Level] (at levels 0-15)
* 2.5[Level]2 - 40.5[Level] + 360 (at levels 16-30)
* 4.5[Level]2 - 162.5[Level] + 2220 (at level 31+)"
*
* @param level the level
* @return the total experience calculated
*/
public static int getExpFromLevel(int level) {
if (level > 30) {
return (int) (4.5 * level * level - 162.5 * level + 2220);
}
if (level > 15) {
return (int) (2.5 * level * level - 40.5 * level + 360);
}
return level * level + 6 * level;
}
/**
* Calculates level based on total experience.
*
* @param exp the total experience
* @return the level calculated
*/
public static double getLevelFromExp(long exp) {
if (exp > 1395) {
return (Math.sqrt(72 * exp - 54215) + 325) / 18;
}
if (exp > 315) {
return Math.sqrt(40 * exp - 7839) / 10 + 8.1;
}
if (exp > 0) {
return Math.sqrt(exp + 9) - 3;
}
return 0;
}
/**
* "The formulas for figuring out how many experience orbs you need to get to the next level are as follows:
* Experience Required = 2[Current Level] + 7 (at levels 0-15)
* 5[Current Level] - 38 (at levels 16-30)
* 9[Current Level] - 158 (at level 31+)"
*/
private static int getExpToNext(int level) {
if (level > 30) {
return 9 * level - 158;
}
if (level > 15) {
return 5 * level - 38;
}
return 2 * level + 7;
}
/**
* Change a Player's exp.
* <p>
* This method should be used in place of {@link Player#giveExp(int)}, which does not properly
* account for different levels requiring different amounts of experience.
*
* @param player the Player affected
* @param exp the amount of experience to add or remove
*/
public static void changeExp(Player player, int exp) {
exp += getExp(player);
if (exp < 0) {
exp = 0;
}
double levelAndExp = getLevelFromExp(exp);
int level = (int) levelAndExp;
player.setLevel(level);
player.setExp((float) (levelAndExp - level));
}
}

View File

@ -1,5 +1,6 @@
package com.songoda.epicenchants.utils;
import com.songoda.epicenchants.enums.EnchantResult;
import org.bukkit.ChatColor;
import java.util.concurrent.ThreadLocalRandom;
@ -21,10 +22,22 @@ public class GeneralUtils {
return ChatColor.translateAlternateColorCodes('&', input).replaceAll(placeholder, toReplace == null ? "" : toReplace.toString());
}
public static int getSlot(int row, int column) {
if (column > 9 || row < 1) {
return 0;
public static String getMessageFromResult(EnchantResult result) {
switch (result) {
case FAILURE:
return "enchant.failure";
case BROKEN_FAILURE:
return "enchant.brokenfailure";
case SUCCESS:
return "enchant.success";
case CONFLICT:
return "enchant.conflict";
case MAXED_OUT:
return "enchant.maxedout";
case ALREADY_APPLIED:
return "enchant.alreadyapplied";
}
return (row - 1) * 9 + column - 1;
return "";
}
}

View File

@ -53,7 +53,7 @@ public class ItemBuilder {
if (section.contains("display-name")) {
String displayName = section.getString("display-name");
for (Placeholder placeholder : placeholders) {
displayName = displayName.replaceAll(placeholder.getPlaceholder(), placeholder.getToReplace().toString());
displayName = displayName.replace(placeholder.getPlaceholder(), placeholder.getToReplace().toString());
}
name(color(displayName));
}
@ -68,12 +68,13 @@ public class ItemBuilder {
lore.remove(i);
Set<String> stringSet = (Set<String>) placeholder.getToReplace();
stringSet.forEach(System.out::println);
lore.addAll(i, stringSet);
} else {
lore.set(i, string.replaceAll(placeholder.getPlaceholder(), placeholder.getToReplace().toString()));
string = string.replace(placeholder.getPlaceholder(), placeholder.getToReplace().toString());
}
}
lore.set(i, string);
}
lore(lore.stream().map(GeneralUtils::color).collect(Collectors.toList()));
}

View File

@ -12,8 +12,8 @@ import lombok.Builder;
import org.bukkit.Location;
import org.bukkit.entity.*;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import static com.songoda.epicenchants.utils.Constants.MONSTER_MAP;
import static java.util.concurrent.ThreadLocalRandom.current;
@Builder
@ -29,7 +29,7 @@ public class MobWrapper {
private boolean hostile;
private LeveledModifier maxAmount;
public void trySpawn(@NotNull Player player, Player opponent, int level, EffectType effectType) {
public void trySpawn(@NotNull Player player, @Nullable LivingEntity opponent, int level, EffectType effectType) {
if (this.effectType != effectType) {
return;
}
@ -75,6 +75,9 @@ public class MobWrapper {
}
NBTEntity nbtEntity = new NBTEntity(entity);
nbtEntity.setBoolean(player.getUniqueId().toString(), true);
NBTList list = nbtEntity.getList("Attributes", NBTType.NBTTagCompound);
for (int j = 0; j < list.size(); j++) {
@ -88,8 +91,6 @@ public class MobWrapper {
lc.setDouble("Base", health.get(level, (int) lc.getDouble("Base")));
}
}
MONSTER_MAP.put(player.getUniqueId(), entity.getUniqueId());
}
}
}

View File

@ -4,8 +4,8 @@ general.nametag.prefix= "&8[&6EpicEnchants&8]"
#Command Messages
command.book.give= "&7You have been given a &6{group-name} &7book."
command.book.gave= "&7You gave {player} a &6{group-name} &7book."
command.book.received= "&7You have been given a &6{enchant} &7book."
command.book.gave= "&7You gave {player} a &6{enchant} &7book."
command.reload= "&6Configuration files reload"
command.filereload.success= "&6{file-name} has been successfully reloaded."
command.filereload.failed= "&c{file-name} failed to be reloaded. &7Please check console for errors."
@ -18,8 +18,10 @@ event.purchase.cannotafford= "&cYou cannot afford this purchase."
event.purchase.success= "&7You successfully purchased a &6{group-name} &7Book."
#Enchant Messages
enchant.invalidmaterial= "&cYou can not apply &6{enchant} to that item."
enchant.invalidmaterial= "&cYou can not apply &6{enchant} &cto that item."
enchant.failure= "&cYou failed to apply &6{enchant}."
enchant.brokenfailure= "&6{enchant} failed to apply and broke your item..."
enchant.brokenfailure= "&6{enchant} &cfailed to apply and broke your item..."
enchant.success= "&aYou have success fully applied &6{enchant}."
enchant.conflict= "&cYou cannot apply this enchant as it conflicts with another enchant."
enchant.maxedout= "&cYou already have that enchant maxed on this item."
enchant.alreadyapplied= "&cYou already have that enchant with that level applied on this item."

View File

@ -1,47 +1,50 @@
#The enchant identifier must be unique
# The enchant identifier must be unique.
identifier: ExampleEnchant
#The max group for this enchant
max-level: 4
# The max level for this enchant.
max-level: 3
#The group of this enchant
# The group of this enchant. Configure the groups in the groups.yml file.
group: SIMPLE
#The book item
# The item that the enchantment book is.
book-item:
material: BOOK
display-name: "&cExampleEnchant {level}"
material: STONE
display-name: "&b&lExampleEnchant {level}"
# The lore on the enchantments books.
lore:
- "&7Drag on to enchant"
- "&cDestroy Rate {destroy_rate}"
- "&aSuccess Rate {success_rate}"
- "&a{success_rate}% Success Rate"
- "&c{destroy_rate}% Destroy Rate"
#Format as seen in the lore of the item
# How the enchant should be formatted on the enchanted item.
applied-format: "&cExampleEnchant {level}"
#What items this enchant can be applied too
# What items this enchant can be applied too.
item-whitelist:
- "DIAMOND_HELMET"
- "IRON_HELMET"
- "LEATHER_HELMET"
# This enchantment can not be applied if then enchantment below is already on the item.
conflicting-enchants:
- "someEnchant"
#Effects
# For a full list of effects, please visit: https://wiki.songoda.com/display/SON/EpicEnchants
effects:
FLY:
type: STATIC_EFFECT
who: WEARER
#The "-1" is added because every effect key has to be unique.
# The "-1" is added because every effect key has to be unique.
POTION-1:
#The EffectType
# The Effect Type
type: DEFENSE_PLAYER_MELEE
#What player should the effect be ran on
# What player should the effect be ran on: WEARER/OPPONENT.
who: WEARER
# Potion Effect that should be applied.
potion-type: SPEED
# Duration of the Potion Effect in seconds.
duration: "10 * {level}"
# Chance that the Effect gets activated.
chance: "20 * {level}"
# Amplifier of 0 = SPEED 1 a Amplifier of 1 = SPEED 2, etc.
amplifier: "{level} - 1"
POTION-2:
type: STATIC_EFFECT
@ -49,19 +52,25 @@ effects:
potion-type: INCREASE_DAMAGE
amplifier: "{level} - 1"
#Chance of spawning when damaged by another player
# Chance of spawning when damaged by another player.
mobs:
#EntityType
# Type of Mob
ZOMBIE:
#Max amount zombies that will be spawned
# Trigger event that spawns the mob.
effect-type: DEFENSE_PLAYER_MELEE
# Max amount mobs that will be spawned.
max-amount: "{level}"
# Chance of trigger the mob spawning.
spawn-percentage: "20 * {level}"
# Drop chance of the mob its equipment upon death.
equipment-drop-chance: "10 * {level}"
# Health of the mob.
health: "3 * {level}"
# Amount of damage the mob deals.
attack-damage: "{level}"
hostile: true
# Display name of the spawned mob
display-name: "&cAngry guy level {level}"
# The equiment that the mob wears
equipment:
helmet:
material: DIAMOND_HELMET

View File

@ -3,7 +3,11 @@ groups:
group-color: "&7"
group-name: "Simple"
group-format: "{group_color} {enchant} {level}"
slots-used: 1
rates:
destroy-min: 10
destroy-max: 100
success-min: 20
success-max: 80
book-item:
material: BOOK
display-name: "&7{enchant} {level}"
@ -14,8 +18,12 @@ groups:
UNIQUE:
group-color: "&a"
group-name: "Unique"
group-format: "{group_color} {enchant} {level}"
slots-used: 1
group-format: "{group_color}{enchant} {level}"
rates:
destroy-min: 10
destroy-max: 100
success-min: 20
success-max: 80
book-item:
material: BOOK
display-name: "{group_color}{enchant} {level}"
@ -26,11 +34,15 @@ groups:
ELITE:
group-color: "&b"
group-name: "Elite"
group-format: "{group_color} {enchant} {level}"
slots-used: 1
group-format: "{group_color}{enchant} {level}"
rates:
destroy-min: 10
destroy-max: 100
success-min: 20
success-max: 80
book-item:
material: BOOK
display-name: "{group_color} {enchant} {level}"
display-name: "{group_color}{enchant} {level}"
lore:
- "&7Drag on to item to enchant"
- "&7Destroy Rate &c{destroy_rate}"
@ -38,11 +50,15 @@ groups:
ULTIMATE:
group-color: "&e"
group-name: "Ultimate"
group-format: "{group_color} {enchant} {level}"
slots-used: 2
group-format: "{group_color}{enchant} {level}"
rates:
destroy-min: 10
destroy-max: 100
success-min: 20
success-max: 80
book-item:
material: BOOK
display-name: "{group_color} {enchant} {level}"
display-name: "{group_color}{enchant} {level}"
lore:
- "&7Drag on to item to enchant"
- "&cDestroy Rate {destroy_rate}"
@ -50,11 +66,15 @@ groups:
LEGENDARY:
group-color: "&6"
group-name: "Legendary"
group-format: "{group_color} {enchant} {level}"
slots-used: 1
group-format: "{group_color}{enchant} {level}"
rates:
destroy-min: 10
destroy-max: 100
success-min: 20
success-max: 80
book-item:
material: BOOK
display-name: "{group_color} {enchant} {level}"
display-name: "{group_color}{enchant} {level}"
lore:
- "&7Drag on to item to enchant"
- "&cDestroy Rate {destroy_rate}"