diff --git a/MMOCore-API/src/main/java/net/Indyuce/mmocore/api/load/DefaultMMOLoader.java b/MMOCore-API/src/main/java/net/Indyuce/mmocore/api/load/DefaultMMOLoader.java
index d29a0ff6..820b85a1 100644
--- a/MMOCore-API/src/main/java/net/Indyuce/mmocore/api/load/DefaultMMOLoader.java
+++ b/MMOCore-API/src/main/java/net/Indyuce/mmocore/api/load/DefaultMMOLoader.java
@@ -23,6 +23,9 @@ public class DefaultMMOLoader extends MMOLoader {
if (config.getKey().equals("stat"))
return new StatTrigger(config);
+ if(config.getKey().equals("unlock_slot"))
+ return new UnlockSlotTrigger(config);
+
if (config.getKey().equals("unlock_skill"))
return new UnlockSkillTrigger(config);
diff --git a/MMOCore-API/src/main/java/net/Indyuce/mmocore/api/player/PlayerData.java b/MMOCore-API/src/main/java/net/Indyuce/mmocore/api/player/PlayerData.java
index 2ff55bf5..07e9391e 100644
--- a/MMOCore-API/src/main/java/net/Indyuce/mmocore/api/player/PlayerData.java
+++ b/MMOCore-API/src/main/java/net/Indyuce/mmocore/api/player/PlayerData.java
@@ -20,10 +20,11 @@ import net.Indyuce.mmocore.api.player.profess.PlayerClass;
import net.Indyuce.mmocore.api.player.profess.SavedClassInformation;
import net.Indyuce.mmocore.api.player.profess.Subclass;
import net.Indyuce.mmocore.api.player.profess.resource.PlayerResource;
-import net.Indyuce.mmocore.api.player.profess.skillbinding.BoundSkillInfo;
+import net.Indyuce.mmocore.skill.binding.BoundSkillInfo;
import net.Indyuce.mmocore.api.player.social.FriendRequest;
import net.Indyuce.mmocore.api.player.stats.PlayerStats;
import net.Indyuce.mmocore.api.quest.PlayerQuests;
+import net.Indyuce.mmocore.api.quest.trigger.SkillModifierTrigger;
import net.Indyuce.mmocore.api.quest.trigger.StatTrigger;
import net.Indyuce.mmocore.api.util.Closable;
import net.Indyuce.mmocore.api.util.MMOCoreUtils;
@@ -43,6 +44,7 @@ import net.Indyuce.mmocore.player.CombatHandler;
import net.Indyuce.mmocore.player.Unlockable;
import net.Indyuce.mmocore.skill.ClassSkill;
import net.Indyuce.mmocore.skill.RegisteredSkill;
+import net.Indyuce.mmocore.skill.binding.SkillSlot;
import net.Indyuce.mmocore.skill.cast.SkillCastingHandler;
import net.Indyuce.mmocore.skilltree.IntegerCoordinates;
import net.Indyuce.mmocore.skilltree.NodeStatus;
@@ -145,8 +147,11 @@ public class PlayerData extends OfflinePlayerData implements Closable, Experienc
this.mmoData = mmoData;
questData = new PlayerQuests(this);
playerStats = new PlayerStats(this);
+
+
}
+
/**
* Update all references after /mmocore reload so there can be garbage
* collection with old plugin objects like class or skill instances.
@@ -207,7 +212,7 @@ public class PlayerData extends OfflinePlayerData implements Closable, Experienc
}
public int countSkillTreePoints(SkillTree skillTree) {
- return nodeLevels.keySet().stream().filter(node -> node.getTree().equals(skillTree)).mapToInt(nodeLevels::get).sum();
+ return nodeLevels.keySet().stream().filter(node -> node.getTree().equals(skillTree)).mapToInt(node -> nodeLevels.get(node) * node.getSkillTreePointsConsumed()).sum();
}
/**
@@ -346,7 +351,7 @@ public class PlayerData extends OfflinePlayerData implements Closable, Experienc
}
public void setNodeLevel(SkillTreeNode node, int nodeLevel) {
- int delta = (nodeLevel - nodeLevels.getOrDefault(node, 0))*node.getSkillTreePointsConsumed();
+ int delta = (nodeLevel - nodeLevels.getOrDefault(node, 0)) * node.getSkillTreePointsConsumed();
pointSpent.put(node.getTree(), pointSpent.getOrDefault(node.getTree(), 0) + delta);
nodeLevels.put(node, nodeLevel);
}
@@ -378,22 +383,23 @@ public class PlayerData extends OfflinePlayerData implements Closable, Experienc
return result;
}
-
-
/**
* @return If the item is unlocked by the player
- * This is used for skills that can be locked & unlocked.
- *
- * Looks at the real value and thus remove the plugin identifier
+ * This is used for skills that can be locked & unlocked.
+ *
+ * Looks at the real value and thus remove the plugin identifier
*/
public boolean hasUnlocked(Unlockable unlockable) {
- String unlockableKey = unlockable.getUnlockNamespacedKey().substring(unlockable.getUnlockNamespacedKey().indexOf(":"));
- return unlockedItems
- .stream()
- .filter(key -> key.substring(key.indexOf(":")).equals(unlockableKey))
- .collect(Collectors.toList()).size() != 0;
+ return hasUnlocked(unlockable.getUnlockNamespacedKey());
+
}
+ public boolean hasUnlocked(String unlockNamespacedKey) {
+ return unlockedItems
+ .stream()
+ .filter(key -> key.equals(unlockNamespacedKey))
+ .collect(Collectors.toList()).size() != 0;
+ }
/**
* Unlocks an item for the player. This is mainly used to unlock skills.
@@ -1176,12 +1182,27 @@ public class PlayerData extends OfflinePlayerData implements Closable, Experienc
if (isOnline())
getStats().updateStats();
- if (profess != null)
+ if (profess != null) {
+
// Loads the classUnlockedSkills
profess.getSkills()
.stream()
.filter(ClassSkill::isUnlockedByDefault)
.forEach(skill -> unlock(skill.getSkill()));
+
+ // Loads the classUnlockedSkills
+ profess.getSkills()
+ .stream()
+ .filter(ClassSkill::isUnlockedByDefault)
+ .forEach(skill -> unlock(skill.getSkill()));
+
+ // Loads the classUnlockedSlots
+ profess.getSlots()
+ .stream()
+ .filter(SkillSlot::isUnlockedByDefault)
+ .forEach(this::unlock);
+ }
+
}
public boolean hasSkillBound(int slot) {
@@ -1208,9 +1229,15 @@ public class PlayerData extends OfflinePlayerData implements Closable, Experienc
public void bindSkill(int slot, ClassSkill skill) {
Validate.notNull(skill, "Skill cannot be null");
//Unbinds the previous skill (Important for passive skills.
+ String skillId = skill.getSkill().getHandler().getId();
if (boundSkills.containsKey(slot))
boundSkills.get(slot).unbind();
if (slot >= 0) {
+ //We apply the skill buffs associated with the slot to the skill.
+ for (SkillModifierTrigger skillBuffTrigger : profess.getSkillSlot(slot).getSkillBuffTriggers())
+ if (skillBuffTrigger.getTargetSkills().contains(skillId))
+ skillBuffTrigger.apply(this, skill.getSkill().getHandler());
+
if (skill.getSkill().getTrigger().isPassive()) {
PassiveSkill passiveSkill = skill.toPassive(this);
passiveSkill.register(mmoData);
@@ -1222,6 +1249,11 @@ public class PlayerData extends OfflinePlayerData implements Closable, Experienc
}
public void unbindSkill(int slot) {
+
+ // We remove the skill buffs associated with the slot from the skill that is .
+ profess.getSkillSlot(slot).getSkillBuffTriggers().forEach(skillBuffTrigger ->
+ skillBuffTrigger.remove(this, boundSkills.get(slot).getClassSkill().getSkill().getHandler()));
+
BoundSkillInfo boundSkillInfo = boundSkills.remove(slot);
boundSkillInfo.unbind();
}
@@ -1245,7 +1277,7 @@ public class PlayerData extends OfflinePlayerData implements Closable, Experienc
* checks if they could potentially upgrade to one of these
*
* @return If the player can change its current class to
- * a subclass
+ * a subclass
*/
@Deprecated
public boolean canChooseSubclass() {
diff --git a/MMOCore-API/src/main/java/net/Indyuce/mmocore/api/player/profess/PlayerClass.java b/MMOCore-API/src/main/java/net/Indyuce/mmocore/api/player/profess/PlayerClass.java
index 5632bde9..94f6dd5b 100644
--- a/MMOCore-API/src/main/java/net/Indyuce/mmocore/api/player/profess/PlayerClass.java
+++ b/MMOCore-API/src/main/java/net/Indyuce/mmocore/api/player/profess/PlayerClass.java
@@ -21,7 +21,7 @@ import net.Indyuce.mmocore.api.player.profess.event.EventTrigger;
import net.Indyuce.mmocore.api.player.profess.resource.ManaDisplayOptions;
import net.Indyuce.mmocore.api.player.profess.resource.PlayerResource;
import net.Indyuce.mmocore.api.player.profess.resource.ResourceRegeneration;
-import net.Indyuce.mmocore.api.player.profess.skillbinding.SkillSlot;
+import net.Indyuce.mmocore.skill.binding.SkillSlot;
import net.Indyuce.mmocore.api.util.MMOCoreUtils;
import net.Indyuce.mmocore.api.util.math.formula.LinearValue;
import net.Indyuce.mmocore.experience.EXPSource;
@@ -185,15 +185,13 @@ public class PlayerClass extends PostLoadObject implements ExperienceObject {
}
// Skill slots
- if (config.contains("skill-slots"))
- for (String key : config.getConfigurationSection("skill-slots").getKeys(false))
- try {
- SkillSlot skillSlot = new SkillSlot(config.getConfigurationSection("skill-slots." + key));
- skillSlots.put(skillSlot.getSlot(), skillSlot);
- } catch (RuntimeException exception) {
- MMOCore.plugin.getLogger().log(Level.WARNING, "Could not load skill slot '" + key + "' from class '"
- + id + "': " + exception.getMessage());
- }
+ Validate.isTrue(config.isConfigurationSection("skill-slots"), "You must define the skills-slots for class " + id);
+ for (int i = 1; i < MMOCore.plugin.configManager.maxSlots + 1; i++) {
+ if (config.contains("skill-slots." + i))
+ skillSlots.put(i, new SkillSlot(config.getConfigurationSection("skill-slots." + i)));
+ else
+ skillSlots.put(i, new SkillSlot(i, 0, "true", "&eSkill Slot " + MMOCoreUtils.intToRoman(i), new ArrayList<>(), false, true, new ArrayList<>()));
+ }
// Class skills
for (RegisteredSkill registered : MMOCore.plugin.skillManager.getAll()) {
@@ -201,7 +199,7 @@ public class PlayerClass extends PostLoadObject implements ExperienceObject {
if (config.contains("skills." + key))
skills.put(key, new ClassSkill(registered, config.getConfigurationSection("skills." + key)));
else
- skills.put(key, new ClassSkill(registered, 1, 1,false));
+ skills.put(key, new ClassSkill(registered, 1, 1, false));
}
// Casting particle
@@ -446,6 +444,10 @@ public class PlayerClass extends PostLoadObject implements ExperienceObject {
return skillSlots.get(slot);
}
+ public Collection getSlots() {
+ return skillSlots.values();
+ }
+
public ClassSkill getSkill(RegisteredSkill skill) {
return getSkill(skill.getHandler().getId());
}
diff --git a/MMOCore-API/src/main/java/net/Indyuce/mmocore/api/player/profess/SavedClassInformation.java b/MMOCore-API/src/main/java/net/Indyuce/mmocore/api/player/profess/SavedClassInformation.java
index 05881478..b307c634 100644
--- a/MMOCore-API/src/main/java/net/Indyuce/mmocore/api/player/profess/SavedClassInformation.java
+++ b/MMOCore-API/src/main/java/net/Indyuce/mmocore/api/player/profess/SavedClassInformation.java
@@ -7,6 +7,7 @@ import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.api.player.attribute.PlayerAttribute;
import net.Indyuce.mmocore.api.util.MMOCoreUtils;
import net.Indyuce.mmocore.player.ClassDataContainer;
+import net.Indyuce.mmocore.skill.ClassSkill;
import net.Indyuce.mmocore.skill.RegisteredSkill;
import net.Indyuce.mmocore.skilltree.SkillTreeNode;
import net.Indyuce.mmocore.skilltree.tree.SkillTree;
@@ -86,6 +87,7 @@ public class SavedClassInformation {
mana = json.has("mana") ? json.get("mana").getAsDouble() : 0;
stamina = json.has("stamina") ? json.get("stamina").getAsDouble() : 0;
stellium = json.has("stellium") ? json.get("stellium").getAsDouble() : 0;
+
if (json.has("attribute"))
for (Entry entry : json.getAsJsonObject("attribute").entrySet())
attributeLevels.put(entry.getKey(), entry.getValue().getAsInt());
diff --git a/MMOCore-API/src/main/java/net/Indyuce/mmocore/api/player/profess/skillbinding/SkillSlot.java b/MMOCore-API/src/main/java/net/Indyuce/mmocore/api/player/profess/skillbinding/SkillSlot.java
deleted file mode 100644
index 3483ae41..00000000
--- a/MMOCore-API/src/main/java/net/Indyuce/mmocore/api/player/profess/skillbinding/SkillSlot.java
+++ /dev/null
@@ -1,63 +0,0 @@
-package net.Indyuce.mmocore.api.player.profess.skillbinding;
-
-import net.Indyuce.mmocore.skill.ClassSkill;
-import org.bukkit.Material;
-import org.bukkit.configuration.ConfigurationSection;
-
-import javax.annotation.Nullable;
-import java.util.List;
-
-public class SkillSlot {
- private final int slot, modelData;
- private final String formula;
- private final String name;
- private final List lore;
- private final Material item;
-
- public SkillSlot(int slot, int modelData, String formula, String name, List lore, Material item) {
- this.slot = slot;
- this.modelData = modelData;
- this.formula = formula;
- this.name = name;
- this.lore = lore;
- this.item = item;
- }
-
- public SkillSlot(ConfigurationSection section) {
- this.slot = Integer.parseInt(section.getName());
- this.formula = section.contains("expression") ? section.getString("expression") : "true";
- this.name = section.getString("name");
- this.lore = section.getStringList("lore");
- this.item = section.contains("item") ? Material.valueOf(section.getString("item")) : null;
- this.modelData = section.getInt("model-data", 0);
- }
-
- public int getSlot() {
- return slot;
- }
-
- public String getName() {
- return name;
- }
-
- public List getLore() {
- return lore;
- }
-
- @Nullable
- public Material getItem() {
- return item;
- }
-
- public boolean hasItem() {
- return item != null;
- }
-
- public int getModelData() {
- return modelData;
- }
-
- public boolean acceptsSkill(ClassSkill classSkill) {
- return classSkill.getSkill().matchesFormula(formula);
- }
-}
diff --git a/MMOCore-API/src/main/java/net/Indyuce/mmocore/api/quest/trigger/SkillModifierTrigger.java b/MMOCore-API/src/main/java/net/Indyuce/mmocore/api/quest/trigger/SkillModifierTrigger.java
index 0ec0ec71..0d2903ad 100644
--- a/MMOCore-API/src/main/java/net/Indyuce/mmocore/api/quest/trigger/SkillModifierTrigger.java
+++ b/MMOCore-API/src/main/java/net/Indyuce/mmocore/api/quest/trigger/SkillModifierTrigger.java
@@ -1,12 +1,14 @@
package net.Indyuce.mmocore.api.quest.trigger;
import io.lumine.mythic.lib.api.MMOLineConfig;
+import io.lumine.mythic.lib.player.modifier.ModifierType;
import io.lumine.mythic.lib.player.skillmod.SkillModifier;
import io.lumine.mythic.lib.skill.handler.SkillHandler;
import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.api.quest.trigger.api.Removable;
import net.Indyuce.mmocore.skill.RegisteredSkill;
+import org.apache.commons.lang.Validate;
import java.util.ArrayList;
import java.util.List;
@@ -14,7 +16,7 @@ import java.util.UUID;
public class SkillModifierTrigger extends Trigger implements Removable {
private final SkillModifier mod;
- private final String modifierKey = TRIGGER_PREFIX + "." + UUID.randomUUID();
+ private final String buffKey = TRIGGER_PREFIX + "." + UUID.randomUUID();
private final double amount;
public SkillModifierTrigger(MMOLineConfig config) {
@@ -22,18 +24,22 @@ public class SkillModifierTrigger extends Trigger implements Removable {
config.validateKeys("modifier");
config.validateKeys("amount");
- config.validateKeys("formula");
config.validateKeys("type");
-
amount = config.getDouble("amount");
String skillModifier = config.getString("modifier");
- String formula = config.getString("formula");
- final List> targetSkills = new ArrayList<>();
- for (RegisteredSkill skill : MMOCore.plugin.skillManager.getAll())
+ String formula = config.getString("formula", "true");
+ String type = config.getString("type").toUpperCase();
+ Validate.isTrue(type.equals("FLAT") || type.equals("RELATIVE"));
+ List> targetSkills = new ArrayList<>();
+ for (RegisteredSkill skill : MMOCore.plugin.skillManager.getAll()) {
if (skill.matchesFormula(formula))
targetSkills.add(skill.getHandler());
+ }
+ mod = new SkillModifier(buffKey, skillModifier, targetSkills, amount, ModifierType.valueOf(type));
+ }
- mod = new SkillModifier(modifierKey, skillModifier, targetSkills, amount);
+ public List> getTargetSkills() {
+ return mod.getSkills();
}
@Override
@@ -45,4 +51,18 @@ public class SkillModifierTrigger extends Trigger implements Removable {
public void remove(PlayerData playerData) {
mod.unregister(playerData.getMMOPlayerData());
}
+
+ /**
+ * Used by skill slots to apply a skillBuff to a specific skill dynamically chosen .
+ */
+ public void apply(PlayerData playerData, SkillHandler> skill) {
+ mod.register(playerData.getMMOPlayerData(), skill);
+ }
+
+ /**
+ * Used by skill slots to remove a skillBuff from a specific skill dynamically chosen.
+ */
+ public void remove(PlayerData playerData, SkillHandler> skill) {
+ mod.unregister(playerData.getMMOPlayerData(), skill);
+ }
}
diff --git a/MMOCore-API/src/main/java/net/Indyuce/mmocore/api/quest/trigger/UnlockSlotTrigger.java b/MMOCore-API/src/main/java/net/Indyuce/mmocore/api/quest/trigger/UnlockSlotTrigger.java
new file mode 100644
index 00000000..3f074498
--- /dev/null
+++ b/MMOCore-API/src/main/java/net/Indyuce/mmocore/api/quest/trigger/UnlockSlotTrigger.java
@@ -0,0 +1,34 @@
+package net.Indyuce.mmocore.api.quest.trigger;
+
+import io.lumine.mythic.lib.api.MMOLineConfig;
+import net.Indyuce.mmocore.MMOCore;
+import net.Indyuce.mmocore.api.player.PlayerData;
+import net.Indyuce.mmocore.skill.binding.SkillSlot;
+import net.Indyuce.mmocore.api.quest.trigger.api.Removable;
+import org.apache.commons.lang.Validate;
+
+
+public class UnlockSlotTrigger extends Trigger implements Removable {
+ private final int slot;
+
+ public UnlockSlotTrigger(MMOLineConfig config) {
+ super(config);
+ config.validateKeys("slot");
+ slot = Integer.parseInt("slot");
+ Validate.isTrue(slot > 0 && slot <= MMOCore.plugin.configManager.maxSlots, "The slot should be between 1 and " + MMOCore.plugin.configManager.maxSlots);
+ }
+
+ @Override
+ public void apply(PlayerData player) {
+ SkillSlot skillSlot = player.getProfess().getSkillSlot(slot);
+ if (!player.hasUnlocked(skillSlot))
+ player.unlock(skillSlot);
+ }
+
+ @Override
+ public void remove(PlayerData player) {
+ SkillSlot skillSlot = player.getProfess().getSkillSlot(slot);
+ if (player.hasUnlocked(skillSlot))
+ player.lock(skillSlot);
+ }
+}
diff --git a/MMOCore-API/src/main/java/net/Indyuce/mmocore/command/rpg/admin/AdminCommandTreeNode.java b/MMOCore-API/src/main/java/net/Indyuce/mmocore/command/rpg/admin/AdminCommandTreeNode.java
index a1cc45dd..18a444b3 100644
--- a/MMOCore-API/src/main/java/net/Indyuce/mmocore/command/rpg/admin/AdminCommandTreeNode.java
+++ b/MMOCore-API/src/main/java/net/Indyuce/mmocore/command/rpg/admin/AdminCommandTreeNode.java
@@ -22,14 +22,14 @@ public class AdminCommandTreeNode extends CommandTreeNode {
addChild(new AttributeCommandTreeNode(this));
addChild(new SkillCommandTreeNode(this));
addChild(new SaveDataTreeNode(this));
-
+ addChild(new SlotCommandTreeNode(this));
addChild(new PointsCommandTreeNode("skill", this, PlayerData::setSkillPoints, PlayerData::giveSkillPoints, PlayerData::getSkillPoints));
addChild(new PointsCommandTreeNode("class", this, PlayerData::setClassPoints, PlayerData::giveClassPoints, PlayerData::getClassPoints));
addChild(new PointsCommandTreeNode("attribute", this, PlayerData::setAttributePoints, PlayerData::giveAttributePoints, PlayerData::getAttributePoints));
addChild(new PointsCommandTreeNode("attr-realloc", this, PlayerData::setAttributeReallocationPoints, PlayerData::giveAttributeReallocationPoints, PlayerData::getAttributeReallocationPoints));
addChild(new PointsCommandTreeNode("skill-realloc", this, PlayerData::setSkillReallocationPoints, PlayerData::giveSkillReallocationPoints, PlayerData::getSkillReallocationPoints));
addChild(new PointsCommandTreeNode("skill-tree-realloc", this, PlayerData::setSkillTreeReallocationPoints, PlayerData::giveSkillTreeReallocationPoints, PlayerData::getSkillTreeReallocationPoints));
- addChild(new SkillTreePointsCommandTreeNode(this,(playerData, integer, s) -> playerData.setSkillTreePoints(s,integer),(playerData, integer, s) -> playerData.giveSkillTreePoints(s,integer),((playerData, s) -> playerData.getSkillTreePoint(s))));
+ addChild(new SkillTreePointsCommandTreeNode(this, (playerData, integer, s) -> playerData.setSkillTreePoints(s, integer), (playerData, integer, s) -> playerData.giveSkillTreePoints(s, integer), ((playerData, s) -> playerData.getSkillTreePoint(s))));
for (PlayerResource res : PlayerResource.values())
addChild(new ResourceCommandTreeNode(res.name().toLowerCase(), this, res));
}
diff --git a/MMOCore-API/src/main/java/net/Indyuce/mmocore/command/rpg/admin/SlotCommandTreeNode.java b/MMOCore-API/src/main/java/net/Indyuce/mmocore/command/rpg/admin/SlotCommandTreeNode.java
new file mode 100644
index 00000000..f7fd32fe
--- /dev/null
+++ b/MMOCore-API/src/main/java/net/Indyuce/mmocore/command/rpg/admin/SlotCommandTreeNode.java
@@ -0,0 +1,155 @@
+package net.Indyuce.mmocore.command.rpg.admin;
+
+import io.lumine.mythic.lib.command.api.CommandTreeNode;
+import io.lumine.mythic.lib.command.api.Parameter;
+import net.Indyuce.mmocore.MMOCore;
+import net.Indyuce.mmocore.api.player.PlayerData;
+import net.Indyuce.mmocore.skill.binding.SkillSlot;
+import net.Indyuce.mmocore.command.api.CommandVerbose;
+import net.Indyuce.mmocore.skill.ClassSkill;
+import org.bukkit.Bukkit;
+import org.bukkit.ChatColor;
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
+
+
+public class SlotCommandTreeNode extends CommandTreeNode {
+ public SlotCommandTreeNode(CommandTreeNode parent) {
+ super(parent, "slot");
+ addChild(new LockSlotCommandTreeNode(this, "lock", true));
+ addChild(new LockSlotCommandTreeNode(this, "unlock", false));
+ addChild(new UnbindSlotCommandTreeNode(this, "unbind"));
+ addChild(new BindSlotCommandTreeNode(this, "bind"));
+ }
+
+ public class LockSlotCommandTreeNode extends CommandTreeNode {
+ private final boolean lock;
+
+ public LockSlotCommandTreeNode(CommandTreeNode parent, String id, boolean lock) {
+ super(parent, id);
+ this.lock = lock;
+ addParameter(Parameter.PLAYER);
+ addParameter(Parameter.AMOUNT);
+ }
+
+ @Override
+ public CommandResult execute(CommandSender sender, String[] args) {
+ if (args.length < 5)
+ return CommandResult.THROW_USAGE;
+ Player player = Bukkit.getPlayer(args[3]);
+ if (player == null) {
+ sender.sendMessage(ChatColor.RED + "Could not find the player called " + args[3] + ".");
+ return CommandResult.FAILURE;
+ }
+ PlayerData playerData = PlayerData.get(player);
+ int slot;
+ try {
+ slot = Integer.parseInt(args[4]);
+ } catch (NumberFormatException e) {
+ sender.sendMessage(ChatColor.RED + args[4] + " is not a valid number.");
+ return CommandResult.FAILURE;
+ }
+ if (slot <= 0) {
+ sender.sendMessage(ChatColor.RED + "The slot can't be negative.");
+ return CommandResult.FAILURE;
+ }
+ SkillSlot skillSlot = playerData.getProfess().getSkillSlot(slot);
+ if (lock) {
+ if (!playerData.hasUnlocked(skillSlot)) {
+ CommandVerbose.verbose(sender, CommandVerbose.CommandType.SKILL, ChatColor.RED + "The skill slot " + skillSlot.getName() + " is already locked" + " for " + player.getName());
+ return CommandResult.SUCCESS;
+ }
+ playerData.lock(skillSlot);
+
+ } else {
+ if (playerData.hasUnlocked(skillSlot)) {
+ CommandVerbose.verbose(sender, CommandVerbose.CommandType.SKILL, ChatColor.RED + "The skill slot " + skillSlot.getName() + " is already unlocked" + " for " + player.getName());
+ return CommandResult.SUCCESS;
+ }
+ playerData.unlock(skillSlot);
+ }
+ CommandVerbose.verbose(sender, CommandVerbose.CommandType.SKILL, ChatColor.GOLD + "The skill slot " + skillSlot.getName() + " is now " + (lock ? "locked" : "unlocked" + " for " + player.getName()));
+ return CommandResult.SUCCESS;
+ }
+ }
+
+
+ public class BindSlotCommandTreeNode extends CommandTreeNode {
+
+ public BindSlotCommandTreeNode(CommandTreeNode parent, String id) {
+ super(parent, id);
+ addParameter(Parameter.PLAYER);
+ addParameter(Parameter.AMOUNT);
+ addParameter(new Parameter("",
+ (explorer, list) -> MMOCore.plugin.skillManager.getAll().forEach(skill -> list.add(skill.getHandler().getId().toUpperCase()))));
+
+ }
+
+ @Override
+ public CommandResult execute(CommandSender sender, String[] args) {
+ if (args.length < 6)
+ return CommandResult.THROW_USAGE;
+ Player player = Bukkit.getPlayer(args[3]);
+ if (player == null) {
+ sender.sendMessage(ChatColor.RED + "Could not find the player called " + args[3] + ".");
+ return CommandResult.FAILURE;
+ }
+ PlayerData playerData = PlayerData.get(player);
+ int slot;
+ try {
+ slot = Integer.parseInt(args[4]);
+ } catch (NumberFormatException e) {
+ sender.sendMessage(ChatColor.RED + args[4] + " is not a valid number.");
+ return CommandResult.FAILURE;
+ }
+ ClassSkill skill = playerData.getProfess().getSkill(args[5]);
+ if (skill == null) {
+ sender.sendMessage(ChatColor.RED + "The player's class doesn't have a skill called " + args[5] + ".");
+ return CommandResult.FAILURE;
+ }
+ playerData.bindSkill(slot, skill);
+
+ CommandVerbose.verbose(sender, CommandVerbose.CommandType.SKILL, ChatColor.GOLD + "The skill " + skill.getSkill().getHandler().getId() + " is now bound to the slot " + slot);
+ return CommandResult.SUCCESS;
+ }
+ }
+
+ public class UnbindSlotCommandTreeNode extends CommandTreeNode {
+
+ public UnbindSlotCommandTreeNode(CommandTreeNode parent, String id) {
+ super(parent, id);
+ addParameter(Parameter.PLAYER);
+ addParameter(Parameter.AMOUNT);
+ }
+
+ @Override
+ public CommandResult execute(CommandSender sender, String[] args) {
+ if (args.length < 5)
+ return CommandResult.THROW_USAGE;
+ Player player = Bukkit.getPlayer(args[3]);
+ if (player == null) {
+ sender.sendMessage(ChatColor.RED + "Could not find the player called " + args[3] + ".");
+ return CommandResult.FAILURE;
+ }
+ PlayerData playerData = PlayerData.get(player);
+ int slot;
+ try {
+ slot = Integer.parseInt(args[4]);
+ } catch (NumberFormatException e) {
+ sender.sendMessage(ChatColor.RED + args[4] + " is not a valid number.");
+ return CommandResult.FAILURE;
+ }
+ String skill = playerData.hasSkillBound(slot) ? playerData.getBoundSkill(slot).getSkill().getHandler().getId() : "none";
+ if (playerData.hasSkillBound(slot))
+ playerData.unbindSkill(slot);
+
+ CommandVerbose.verbose(sender, CommandVerbose.CommandType.SKILL, ChatColor.GOLD + "The skill " + skill + " has been unbounded from the slot " + slot);
+ return CommandResult.SUCCESS;
+ }
+ }
+
+ @Override
+ public CommandResult execute(CommandSender sender, String[] args) {
+ return CommandResult.THROW_USAGE;
+ }
+}
diff --git a/MMOCore-API/src/main/java/net/Indyuce/mmocore/gui/SkillList.java b/MMOCore-API/src/main/java/net/Indyuce/mmocore/gui/SkillList.java
index 09df079d..ee71e003 100644
--- a/MMOCore-API/src/main/java/net/Indyuce/mmocore/gui/SkillList.java
+++ b/MMOCore-API/src/main/java/net/Indyuce/mmocore/gui/SkillList.java
@@ -4,8 +4,9 @@ import io.lumine.mythic.lib.MythicLib;
import io.lumine.mythic.lib.api.item.ItemTag;
import io.lumine.mythic.lib.api.item.NBTItem;
import net.Indyuce.mmocore.MMOCore;
+import net.Indyuce.mmocore.api.SoundEvent;
import net.Indyuce.mmocore.api.player.PlayerData;
-import net.Indyuce.mmocore.api.player.profess.skillbinding.SkillSlot;
+import net.Indyuce.mmocore.skill.binding.SkillSlot;
import net.Indyuce.mmocore.api.util.MMOCoreUtils;
import net.Indyuce.mmocore.gui.api.EditableInventory;
import net.Indyuce.mmocore.gui.api.GeneratedInventory;
@@ -15,7 +16,6 @@ import net.Indyuce.mmocore.gui.api.item.Placeholders;
import net.Indyuce.mmocore.gui.api.item.SimplePlaceholderItem;
import net.Indyuce.mmocore.skill.ClassSkill;
import net.Indyuce.mmocore.skill.RegisteredSkill;
-import net.Indyuce.mmocore.api.SoundEvent;
import org.apache.commons.lang.Validate;
import org.bukkit.ChatColor;
import org.bukkit.Material;
@@ -27,6 +27,7 @@ import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import java.util.ArrayList;
+import java.util.Comparator;
import java.util.List;
import java.util.logging.Level;
import java.util.stream.Collectors;
@@ -64,49 +65,7 @@ public class SkillList extends EditableInventory {
}
if (function.equals("slot"))
- return new SlotItem(config) {
- @Override
- public ItemStack display(SkillViewerInventory inv, int n) {
- if (!inv.getPlayerData().getProfess().hasSlot(n+1)) {
- return new ItemStack(Material.AIR);
- }
- SkillSlot skillSlot = inv.getPlayerData().getProfess().getSkillSlot(n+1);
- ItemStack item = super.display(inv, n);
- if (!inv.getPlayerData().hasSkillBound(n+1)) {
- //If there is an item filled in the slot config it shows it, else shows the default item.
- Material material = skillSlot.hasItem() ? skillSlot.getItem() : super.emptyMaterial;
- int customModelData = skillSlot.hasItem() ? skillSlot.getModelData() : super.emptyCMD;
- item.setType(material);
- ItemMeta meta = item.getItemMeta();
- meta.setDisplayName(MMOCore.plugin.placeholderParser.parse(inv.getPlayerData().getPlayer(),skillSlot.getName()));
- List lore=skillSlot.getLore()
- .stream()
- .map(str->MMOCore.plugin.placeholderParser.parse(inv.getPlayerData().getPlayer(),str))
- .collect(Collectors.toList());
- meta.setLore(lore);
- if (MythicLib.plugin.getVersion().isStrictlyHigher(1, 13)) {
- meta.setCustomModelData(customModelData);
- }
- item.setItemMeta(meta);
-
- }
-
- return item;
- }
-
- /**
- * This should only be called when there is a skill bound.
- */
- @Override
- public Placeholders getPlaceholders(SkillViewerInventory inv, int n) {
- Placeholders holders = super.getPlaceholders(inv, n);
- String none = MythicLib.plugin.parseColors(config.getString("no-skill"));
- RegisteredSkill skill = inv.getPlayerData().hasSkillBound(n+1) ? inv.getPlayerData().getBoundSkill(n+1).getSkill() : null;
- holders.register("skill", skill == null ? none : skill.getName());
- return holders;
- }
-
- };
+ return new SlotItem(config);
if (function.equals("previous"))
return new SimplePlaceholderItem(config) {
@@ -198,16 +157,49 @@ public class SkillList extends EditableInventory {
emptyCMD = config.getInt("empty-custom-model-data", getModelData());
}
+ @Override
+ public ItemStack display(SkillViewerInventory inv, int n) {
+ if (!inv.getPlayerData().hasUnlocked("slot:" + (n+1))) {
+ return new ItemStack(Material.AIR);
+ }
+ SkillSlot skillSlot = inv.getPlayerData().getProfess().getSkillSlot(n + 1);
+ ItemStack item = super.display(inv, n);
+ if (!inv.getPlayerData().hasSkillBound(n + 1)) {
+ //If there is an item filled in the slot config it shows it, else shows the default item.
+ Material material = skillSlot.hasItem() ? skillSlot.getItem() : emptyMaterial;
+ int customModelData = skillSlot.hasItem() ? skillSlot.getModelData() : emptyCMD;
+ item.setType(material);
+ ItemMeta meta = item.getItemMeta();
+ meta.setDisplayName(MMOCore.plugin.placeholderParser.parse(inv.getPlayerData().getPlayer(), skillSlot.getName()));
+ List lore = skillSlot.getLore()
+ .stream()
+ .map(str -> MMOCore.plugin.placeholderParser.parse(inv.getPlayerData().getPlayer(), str))
+ .collect(Collectors.toList());
+ meta.setLore(lore);
+ if (MythicLib.plugin.getVersion().isStrictlyHigher(1, 13)) {
+ meta.setCustomModelData(customModelData);
+ }
+ item.setItemMeta(meta);
+
+ }
+
+ return item;
+ }
+
+ /**
+ * This should only be called when there is a skill bound.
+ */
@Override
public Placeholders getPlaceholders(SkillViewerInventory inv, int n) {
- RegisteredSkill selected = inv.selected == null ? null : inv.selected.getSkill();
+ RegisteredSkill selected = inv.selected.getSkill();
Placeholders holders = new Placeholders();
holders.register("index", "" + (n + 1));
holders.register("slot", MMOCoreUtils.intToRoman(n + 1));
holders.register("selected", selected == null ? none : selected.getName());
-
+ RegisteredSkill skill = inv.getPlayerData().hasSkillBound(n + 1) ? inv.getPlayerData().getBoundSkill(n + 1).getSkill() : null;
+ holders.register("skill", skill == null ? none : skill.getName());
return holders;
}
@@ -315,7 +307,7 @@ public class SkillList extends EditableInventory {
private final List skillSlots;
private final List slotSlots;
- //The skill the player Selected
+ // Skill the player selected
private ClassSkill selected;
private int page = 0;
@@ -323,9 +315,11 @@ public class SkillList extends EditableInventory {
super(playerData, editable);
skills = playerData.getProfess().getSkills()
.stream()
- .filter((classSkill)->playerData.hasUnlocked(classSkill.getSkill()))
+ .filter((classSkill) -> playerData.hasUnlocked(classSkill.getSkill()))
+ .sorted(Comparator.comparingInt(ClassSkill::getUnlockLevel))
.collect(Collectors.toList());
skillSlots = getEditable().getByFunction("skill").getSlots();
+
Validate.notNull(getEditable().getByFunction("slot"), "Your skill GUI config file is out-of-date, please regenerate it.");
slotSlots = getEditable().getByFunction("slot").getSlots();
selected = skills.get(page * skillSlots.size());
@@ -396,8 +390,14 @@ public class SkillList extends EditableInventory {
* binding or unbinding skills.
*/
if (item.getFunction().equals("slot")) {
- int index = slotSlots.indexOf(context.getSlot())+1;
- SkillSlot skillSlot=playerData.getProfess().getSkillSlot(index);
+ int index = slotSlots.indexOf(context.getSlot()) + 1;
+ SkillSlot skillSlot = playerData.getProfess().getSkillSlot(index);
+ //Select if the player is doing Shift Left Click
+ if(context.getClickType() ==ClickType.SHIFT_LEFT){
+ if(playerData.hasSkillBound(index))
+ selected=playerData.getBoundSkill(index);
+ return;
+ }
// unbind if there is a current spell.
if (context.getClickType() == ClickType.RIGHT) {
if (!playerData.hasSkillBound(index)) {
@@ -405,22 +405,30 @@ public class SkillList extends EditableInventory {
player.playSound(player.getLocation(), Sound.ENTITY_VILLAGER_NO, 1, 2);
return;
}
+ if(!playerData.getProfess().getSkillSlot(index).canManuallyBind()){
+ MMOCore.plugin.configManager.getSimpleMessage("cant-manually-bind").send(player);
+ player.playSound(player.getLocation(), Sound.ENTITY_VILLAGER_NO, 1, 2);
+ return;
+ }
player.playSound(player.getLocation(), Sound.ENTITY_EXPERIENCE_ORB_PICKUP, 1, 2);
playerData.unbindSkill(index);
open();
return;
}
- if (selected == null)
- return;
-
if (!playerData.hasSkillUnlocked(selected)) {
MMOCore.plugin.configManager.getSimpleMessage("not-unlocked-skill").send(player);
player.playSound(player.getLocation(), Sound.ENTITY_VILLAGER_NO, 1, 2);
return;
}
- if(!skillSlot.acceptsSkill(selected)){
+ if (!skillSlot.canManuallyBind()){
+ MMOCore.plugin.configManager.getSimpleMessage("cant-manually-bind").send(player);
+ player.playSound(player.getLocation(), Sound.ENTITY_VILLAGER_NO, 1, 2);
+ return;
+ }
+
+ if (!skillSlot.acceptsSkill(selected)){
MMOCore.plugin.configManager.getSimpleMessage("not-compatible-skill").send(player);
player.playSound(player.getLocation(), Sound.ENTITY_VILLAGER_NO, 1, 2);
return;
diff --git a/MMOCore-API/src/main/java/net/Indyuce/mmocore/manager/ConfigManager.java b/MMOCore-API/src/main/java/net/Indyuce/mmocore/manager/ConfigManager.java
index eab332ab..1f87638b 100644
--- a/MMOCore-API/src/main/java/net/Indyuce/mmocore/manager/ConfigManager.java
+++ b/MMOCore-API/src/main/java/net/Indyuce/mmocore/manager/ConfigManager.java
@@ -34,7 +34,7 @@ public class ConfigManager {
public long combatLogTimer, lootChestExpireTime, lootChestPlayerCooldown, globalSkillCooldown;
public double lootChestsChanceWeight, dropItemsChanceWeight, fishingDropsChanceWeight, partyMaxExpSplitRange, pvpModeToggleOnCooldown, pvpModeToggleOffCooldown, pvpModeCombatCooldown,
pvpModeCombatTimeout, pvpModeInvulnerabilityTimeRegionChange, pvpModeInvulnerabilityTimeCommand, pvpModeRegionEnterCooldown, pvpModeRegionLeaveCooldown;
- public int maxPartyLevelDifference, maxBoundActiveSkills, maxBoundPassiveSkills, minCombatLevel, maxCombatLevelDifference;
+ public int maxPartyLevelDifference, maxSlots, minCombatLevel, maxCombatLevelDifference;
public final List combatLogDamageCauses = new ArrayList<>();
private final FileConfiguration messages;
@@ -157,8 +157,7 @@ public class ConfigManager {
canCreativeCast = MMOCore.plugin.getConfig().getBoolean("can-creative-cast");
cobbleGeneratorXP = MMOCore.plugin.getConfig().getBoolean("should-cobblestone-generators-give-exp");
saveDefaultClassInfo = MMOCore.plugin.getConfig().getBoolean("save-default-class-info");
- maxBoundActiveSkills = MMOCore.plugin.getConfig().getInt("max-bound-active-skills", 6);
- maxBoundPassiveSkills = MMOCore.plugin.getConfig().getInt("max-bound-passive-skills", 3);
+ maxSlots = MMOCore.plugin.getConfig().getInt("max-slots");
overrideVanillaExp = MMOCore.plugin.getConfig().getBoolean("override-vanilla-exp");
}
diff --git a/MMOCore-API/src/main/java/net/Indyuce/mmocore/manager/data/mysql/MMOCoreDataSynchronizer.java b/MMOCore-API/src/main/java/net/Indyuce/mmocore/manager/data/mysql/MMOCoreDataSynchronizer.java
index 10e87a87..712f4a18 100644
--- a/MMOCore-API/src/main/java/net/Indyuce/mmocore/manager/data/mysql/MMOCoreDataSynchronizer.java
+++ b/MMOCore-API/src/main/java/net/Indyuce/mmocore/manager/data/mysql/MMOCoreDataSynchronizer.java
@@ -71,9 +71,11 @@ public class MMOCoreDataSynchronizer extends DataSynchronizer {
}
data.setupSkillTree();
Set unlockedItems = new HashSet<>();
- JsonArray unlockedItemsArray = new JsonParser().parse(result.getString("unlocked_items")).getAsJsonArray();
- for (JsonElement item : unlockedItemsArray)
- unlockedItems.add(item.getAsString());
+ if (!isEmpty(result.getString("unlocked_items"))) {
+ JsonArray unlockedItemsArray = new JsonParser().parse(result.getString("unlocked_items")).getAsJsonArray();
+ for (JsonElement item : unlockedItemsArray)
+ unlockedItems.add(item.getAsString());
+ }
data.setUnlockedItems(unlockedItems);
if (!isEmpty(result.getString("guild"))) {
Guild guild = MMOCore.plugin.dataProvider.getGuildManager().getGuild(result.getString("guild"));
diff --git a/MMOCore-API/src/main/java/net/Indyuce/mmocore/manager/data/yaml/YAMLPlayerDataManager.java b/MMOCore-API/src/main/java/net/Indyuce/mmocore/manager/data/yaml/YAMLPlayerDataManager.java
index 317cdd40..64745961 100644
--- a/MMOCore-API/src/main/java/net/Indyuce/mmocore/manager/data/yaml/YAMLPlayerDataManager.java
+++ b/MMOCore-API/src/main/java/net/Indyuce/mmocore/manager/data/yaml/YAMLPlayerDataManager.java
@@ -6,6 +6,7 @@ import net.Indyuce.mmocore.api.player.OfflinePlayerData;
import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.api.player.profess.PlayerClass;
import net.Indyuce.mmocore.api.player.profess.SavedClassInformation;
+import net.Indyuce.mmocore.api.util.MMOCoreUtils;
import net.Indyuce.mmocore.guild.provided.Guild;
import net.Indyuce.mmocore.manager.data.DataProvider;
import net.Indyuce.mmocore.manager.data.PlayerDataManager;
@@ -80,10 +81,7 @@ public class YAMLPlayerDataManager extends PlayerDataManager {
if (config.contains("times-claimed"))
- for (
- String key : config.getConfigurationSection("times-claimed").
-
- getKeys(false)) {
+ for (String key : config.getConfigurationSection("times-claimed").getKeys(false)) {
ConfigurationSection section = config.getConfigurationSection("times-claimed." + key);
if (section != null)
for (String key1 : section.getKeys(false)) {
@@ -97,8 +95,7 @@ public class YAMLPlayerDataManager extends PlayerDataManager {
}
data.setUnlockedItems(config.getStringList("unlocked-items").stream().collect(Collectors.toSet()));
- for (
- SkillTreeNode node : MMOCore.plugin.skillTreeManager.getAllNodes()) {
+ for (SkillTreeNode node : MMOCore.plugin.skillTreeManager.getAllNodes()) {
data.setNodeLevel(node, config.getInt("skill-tree-level." + node.getFullId(), 0));
}
data.setupSkillTree();
@@ -127,12 +124,8 @@ public class YAMLPlayerDataManager extends PlayerDataManager {
data.setStamina(config.contains("stamina") ? config.getDouble("stamina") : data.getStats().getStat("MAX_STAMINA"));
data.setStellium(config.contains("stellium") ? config.getDouble("stellium") : data.getStats().getStat("MAX_STELLIUM"));
- if (data.isOnline()) {
- double health = config.contains("health") ? config.getDouble("health") : data.getStats().getStat("MAX_HEALTH");
- health = health == 0 ? 20 : health;
- health = Math.min(health, data.getPlayer().getAttribute(Attribute.GENERIC_MAX_HEALTH).getValue());
- data.getPlayer().setHealth(health);
- }
+ if (data.isOnline())
+ data.getPlayer().setHealth(MMOCoreUtils.fixResource(config.getDouble("health"), data.getPlayer().getAttribute(Attribute.GENERIC_MAX_HEALTH).getValue()));
data.setFullyLoaded();
}
diff --git a/MMOCore-API/src/main/java/net/Indyuce/mmocore/player/DefaultPlayerData.java b/MMOCore-API/src/main/java/net/Indyuce/mmocore/player/DefaultPlayerData.java
index a8fb4e65..b03f33e9 100644
--- a/MMOCore-API/src/main/java/net/Indyuce/mmocore/player/DefaultPlayerData.java
+++ b/MMOCore-API/src/main/java/net/Indyuce/mmocore/player/DefaultPlayerData.java
@@ -130,7 +130,7 @@ public class DefaultPlayerData implements ClassDataContainer {
}
@Override
- public Map mapBoundSkills() {
+ public Map mapBoundSkills() {
return new HashMap<>();
}
diff --git a/MMOCore-API/src/main/java/net/Indyuce/mmocore/skill/RegisteredSkill.java b/MMOCore-API/src/main/java/net/Indyuce/mmocore/skill/RegisteredSkill.java
index 46e9823f..cbbfa0ef 100644
--- a/MMOCore-API/src/main/java/net/Indyuce/mmocore/skill/RegisteredSkill.java
+++ b/MMOCore-API/src/main/java/net/Indyuce/mmocore/skill/RegisteredSkill.java
@@ -41,9 +41,9 @@ public class RegisteredSkill implements Unlockable {
categories = config.getStringList("categories");
categories.add(getHandler().getId());
if (triggerType.isPassive())
- categories.add("passive");
+ categories.add("PASSIVE");
else
- categories.add("active");
+ categories.add("ACTIVE");
// Load default modifier formulas
for (String mod : handler.getModifiers())
@@ -139,7 +139,7 @@ public class RegisteredSkill implements Unlockable {
String parsedExpression = formula;
for (String category : categories)
parsedExpression = parsedExpression.replace("<" + category + ">", "true");
- parsedExpression = parsedExpression.replaceAll("<.*>", "false");
+ parsedExpression = parsedExpression.replaceAll("<.*?>", "false");
try {
return (boolean) MythicLib.plugin.getInterpreter().eval(parsedExpression);
} catch (EvalError error) {
diff --git a/MMOCore-API/src/main/java/net/Indyuce/mmocore/api/player/profess/skillbinding/BoundSkillInfo.java b/MMOCore-API/src/main/java/net/Indyuce/mmocore/skill/binding/BoundSkillInfo.java
similarity index 84%
rename from MMOCore-API/src/main/java/net/Indyuce/mmocore/api/player/profess/skillbinding/BoundSkillInfo.java
rename to MMOCore-API/src/main/java/net/Indyuce/mmocore/skill/binding/BoundSkillInfo.java
index d2b948df..1d7920de 100644
--- a/MMOCore-API/src/main/java/net/Indyuce/mmocore/api/player/profess/skillbinding/BoundSkillInfo.java
+++ b/MMOCore-API/src/main/java/net/Indyuce/mmocore/skill/binding/BoundSkillInfo.java
@@ -1,4 +1,4 @@
-package net.Indyuce.mmocore.api.player.profess.skillbinding;
+package net.Indyuce.mmocore.skill.binding;
import io.lumine.mythic.lib.player.skill.PassiveSkill;
import net.Indyuce.mmocore.api.player.PlayerData;
@@ -27,12 +27,12 @@ public class BoundSkillInfo {
* Used on update to refresh the classSkill & all references to old data.
*/
public BoundSkillInfo(BoundSkillInfo info) {
- this.playerData=info.getPlayerData();
- this.classSkill= Objects.requireNonNull(playerData.getProfess().getSkill(info.getClassSkill().getSkill()));
+ this.playerData = info.getPlayerData();
+ this.classSkill = Objects.requireNonNull(playerData.getProfess().getSkill(info.getClassSkill().getSkill()));
info.unbind();
PassiveSkill passiveSkill = classSkill.toPassive(playerData);
passiveSkill.register(playerData.getMMOPlayerData());
- this.passiveSkillUUID=passiveSkill.getUniqueId();
+ this.passiveSkillUUID = passiveSkill.getUniqueId();
}
public ClassSkill getClassSkill() {
@@ -55,7 +55,7 @@ public class BoundSkillInfo {
playerData.getMMOPlayerData().getPassiveSkillMap().removeModifier(passiveSkillUUID);
PassiveSkill passiveSkill = classSkill.toPassive(playerData);
passiveSkill.register(playerData.getMMOPlayerData());
- this.passiveSkillUUID=passiveSkill.getUniqueId();
+ this.passiveSkillUUID = passiveSkill.getUniqueId();
}
}
diff --git a/MMOCore-API/src/main/java/net/Indyuce/mmocore/skill/binding/SkillSlot.java b/MMOCore-API/src/main/java/net/Indyuce/mmocore/skill/binding/SkillSlot.java
new file mode 100644
index 00000000..9af1ccea
--- /dev/null
+++ b/MMOCore-API/src/main/java/net/Indyuce/mmocore/skill/binding/SkillSlot.java
@@ -0,0 +1,116 @@
+package net.Indyuce.mmocore.skill.binding;
+
+import io.lumine.mythic.lib.api.MMOLineConfig;
+import net.Indyuce.mmocore.MMOCore;
+import net.Indyuce.mmocore.api.player.PlayerData;
+import net.Indyuce.mmocore.player.Unlockable;
+import net.Indyuce.mmocore.api.quest.trigger.SkillModifierTrigger;
+import net.Indyuce.mmocore.skill.ClassSkill;
+import org.bukkit.Material;
+import org.bukkit.configuration.ConfigurationSection;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class SkillSlot implements Unlockable {
+ private final int slot, modelData;
+ private final String formula;
+ private final String name;
+ private final List lore;
+
+ private final boolean isUnlockedByDefault;
+
+ private final boolean canManuallyBind;
+
+ private final List skillBuffTriggers;
+
+ private Material item;
+
+ public SkillSlot(int slot, int modelData, String formula, String name, List lore, boolean isUnlockedByDefault, boolean canManuallyBind, List skillBuffTriggers) {
+ this.slot = slot;
+ this.modelData = modelData;
+ this.formula = formula;
+ this.name = name;
+ this.lore = lore;
+ this.canManuallyBind = canManuallyBind;
+ this.isUnlockedByDefault = isUnlockedByDefault;
+ this.skillBuffTriggers = skillBuffTriggers;
+ }
+
+ public SkillSlot(ConfigurationSection section) {
+ this.slot = Integer.parseInt(section.getName());
+ this.formula = section.contains("formula") ? section.getString("formula") : "true";
+ this.name = section.getString("name");
+ this.lore = section.getStringList("lore");
+ if (section.contains("item"))
+ this.item = Material.valueOf(section.getString("item"));
+ this.modelData = section.getInt("model-data", 0);
+ isUnlockedByDefault = section.getBoolean("unlocked-by-default", true);
+ canManuallyBind = section.getBoolean("can-manually-bind", true);
+ skillBuffTriggers = new ArrayList<>();
+ if (section.contains("skill-buffs"))
+ for (String skillBuff : section.getStringList("skill-buffs"))
+ if (skillBuff.startsWith("skill_buff"))
+ skillBuffTriggers.add((SkillModifierTrigger) MMOCore.plugin.loadManager.loadTrigger(new MMOLineConfig(skillBuff)));
+ }
+
+ public int getSlot() {
+ return slot;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public List getLore() {
+ return lore;
+ }
+
+ public Material getItem() {
+ return item;
+ }
+
+ public boolean hasItem() {
+ return item != null;
+ }
+
+ public int getModelData() {
+ return modelData;
+ }
+
+ public boolean isUnlockedByDefault() {
+ return isUnlockedByDefault;
+ }
+
+ public List getSkillBuffTriggers() {
+ return skillBuffTriggers;
+ }
+
+ public boolean canManuallyBind() {
+ return canManuallyBind;
+ }
+
+ public boolean acceptsSkill(ClassSkill classSkill) {
+ return classSkill.getSkill().matchesFormula(formula);
+ }
+
+ @Override
+ public String getUnlockNamespacedKey() {
+ return "slot:" + slot;
+ }
+
+ /**
+ * If we lock a slot that had a skill bound
+ * to it we first unbind the attached skill.
+ */
+ @Override
+ public void whenLocked(PlayerData playerData) {
+ if (playerData.hasSkillBound(slot))
+ playerData.unbindSkill(slot);
+ }
+
+ @Override
+ public void whenUnlocked(PlayerData playerData) {
+
+ }
+}
diff --git a/MMOCore-Dist/src/main/resources/config.yml b/MMOCore-Dist/src/main/resources/config.yml
index a796b374..cf27fcae 100644
--- a/MMOCore-Dist/src/main/resources/config.yml
+++ b/MMOCore-Dist/src/main/resources/config.yml
@@ -197,16 +197,14 @@ death-exp-loss:
# Percentage of current EXP you lose when dying.
percent: 30
-#Default max bound active and passive skills.
-#These value can be modified for each class in the class yml.
-max-bound-active-skills: 6
+#Maximum number of slot. This means that you can't unlock a slot greater than max-slots. (The slot count starts at 1 & end at max-slots).
+max-slots: 8
#If you want players to bound their passive skills.
#If false, all the passive skills unlocked will be active
#Also set max-bound-passive-skills to 0 if seting passive-skill-need-bound to false.
passive-skill-need-bound: true
-max-bound-passive-skills: 3
# Fun extra RPG feature that switches the player's hotbar with
# the 9 lower row items of his inventory. This allows the player
diff --git a/MMOCore-Dist/src/main/resources/default/gui/skill-list.yml b/MMOCore-Dist/src/main/resources/default/gui/skill-list.yml
index 0e88dd1a..444624e9 100644
--- a/MMOCore-Dist/src/main/resources/default/gui/skill-list.yml
+++ b/MMOCore-Dist/src/main/resources/default/gui/skill-list.yml
@@ -64,6 +64,7 @@ items:
- ''
- '&e► Left click to bind {selected}.'
- '&e► Right click to unbind.'
+ - '&e► Shift left click to select.'
skill-level:
slots: [ 6,15,24,33,42,51 ]
function: level
diff --git a/MMOCore-Dist/src/main/resources/default/messages.yml b/MMOCore-Dist/src/main/resources/default/messages.yml
index d091fa67..f4bcace5 100644
--- a/MMOCore-Dist/src/main/resources/default/messages.yml
+++ b/MMOCore-Dist/src/main/resources/default/messages.yml
@@ -203,6 +203,7 @@ upgrade-skill: '&eYour &6{skill} &eis now Level &6{level}&e!'
not-unlocked-skill: '&cYou have not unlocked that skill yet.'
no-skill-bound: '&cYou don''t have any skill bound to this slot.'
not-compatible-skill: '&cThe selected skill is not compatible with this slot.'
+cant-manually-bind: "&cYou can't manually bind/unbind a skill to this slot."
skill-max-level-hit: '&cYou already hit the max level for that skill.'
no-skill-placeholder: 'No Skill Bound'
not-skill-reallocation-point: '&cYou do not have 1 skill reallocation point.'