From c1f3829e63b412d122e1224ee6a2e7560f0968cb Mon Sep 17 00:00:00 2001 From: Indyuce Date: Fri, 24 Dec 2021 15:19:58 +0100 Subject: [PATCH] experience tables --- .../mmocore/experience/PlayerProfessions.java | 62 ++++++++-- .../mmocore/experience/Profession.java | 101 ++++++---------- .../experience/droptable/ExperienceItem.java | 79 +++++++++++++ .../experience/droptable/ExperienceTable.java | 55 +++++++++ .../mmocore/manager/ConfigManager.java | 1 + .../mmocore/manager/ExperienceManager.java | 109 +++++++++++++----- .../mmocore/manager/MMOCoreManager.java | 13 +++ src/main/resources/default/exp-tables.yml | 46 ++++++++ 8 files changed, 363 insertions(+), 103 deletions(-) create mode 100644 src/main/java/net/Indyuce/mmocore/experience/droptable/ExperienceItem.java create mode 100644 src/main/java/net/Indyuce/mmocore/experience/droptable/ExperienceTable.java create mode 100644 src/main/java/net/Indyuce/mmocore/manager/MMOCoreManager.java create mode 100644 src/main/resources/default/exp-tables.yml diff --git a/src/main/java/net/Indyuce/mmocore/experience/PlayerProfessions.java b/src/main/java/net/Indyuce/mmocore/experience/PlayerProfessions.java index 4392954c..8f72bf32 100644 --- a/src/main/java/net/Indyuce/mmocore/experience/PlayerProfessions.java +++ b/src/main/java/net/Indyuce/mmocore/experience/PlayerProfessions.java @@ -11,7 +11,10 @@ import net.Indyuce.mmocore.api.event.PlayerLevelUpEvent; import net.Indyuce.mmocore.api.player.PlayerData; import net.Indyuce.mmocore.api.util.MMOCoreUtils; import net.Indyuce.mmocore.api.util.math.particle.SmallParticleEffect; +import net.Indyuce.mmocore.experience.droptable.ExperienceItem; +import net.Indyuce.mmocore.experience.droptable.ExperienceTable; import net.Indyuce.mmocore.manager.SoundManager; +import org.apache.commons.lang.Validate; import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.Location; @@ -26,6 +29,7 @@ import java.util.Map.Entry; public class PlayerProfessions { private final Map exp = new HashMap<>(); private final Map level = new HashMap<>(); + private final Map timesClaimed = new HashMap<>(); private final PlayerData playerData; public PlayerProfessions(PlayerData playerData) { @@ -39,6 +43,11 @@ public class PlayerProfessions { level.put(key, config.getInt(key + ".level")); } + if (config.contains("times-claimed")) + // Watch out for the deep section lookup + for (String key : config.getConfigurationSection("times-claimed").getKeys(true)) + this.timesClaimed.put(key, config.getInt("times-claimed." + key)); + return this; } @@ -47,6 +56,8 @@ public class PlayerProfessions { config.set(id + ".exp", exp.get(id)); for (String id : level.keySet()) config.set(id + ".level", level.get(id)); + + timesClaimed.forEach((key, value) -> config.set("times-claimed." + key, value)); } public String toJsonString() { @@ -58,18 +69,29 @@ public class PlayerProfessions { json.add(profession.getId(), object); } + + JsonObject timesClaimed = new JsonObject(); + this.timesClaimed.forEach((key, value) -> timesClaimed.addProperty(key, value)); + json.add("timesClaimed", timesClaimed); + return json.toString(); } public void load(String json) { - Gson parser = new Gson(); - JsonObject jo = parser.fromJson(json, JsonObject.class); - for (Entry entry : jo.entrySet()) { + JsonObject obj = new Gson().fromJson(json, JsonObject.class); + + // Load profession exp and levels + for (Entry entry : obj.entrySet()) if (MMOCore.plugin.professionManager.has(entry.getKey())) { - exp.put(entry.getKey(), entry.getValue().getAsJsonObject().get("exp").getAsInt()); - level.put(entry.getKey(), entry.getValue().getAsJsonObject().get("level").getAsInt()); + JsonObject value = entry.getValue().getAsJsonObject(); + exp.put(entry.getKey(), value.get("exp").getAsInt()); + level.put(entry.getKey(), value.get("level").getAsInt()); } - } + + // Load times claimed + if (obj.has("timesClaimed")) + for (Entry entry : obj.getAsJsonObject("timesClaimed").entrySet()) + timesClaimed.put(entry.getKey(), entry.getValue().getAsInt()); } public PlayerData getPlayerData() { @@ -129,7 +151,9 @@ public class PlayerProfessions { } public void giveExperience(Profession profession, double value, EXPSource source, @Nullable Location hologramLocation) { - if (hasReachedMaxLevel(profession)) { + Validate.isTrue(playerData.isOnline(), "Cannot give experience to offline player"); + + if (hasReachedMaxLevel(profession)) { setExperience(profession, 0); return; } @@ -137,7 +161,7 @@ public class PlayerProfessions { value = MMOCore.plugin.boosterManager.calculateExp(profession, value); // display hologram - if (hologramLocation != null && playerData.isOnline()) + if (hologramLocation != null ) MMOCoreUtils.displayIndicator(hologramLocation.add(.5, 1.5, .5), MMOCore.plugin.configManager.getSimpleMessage("exp-hologram", "exp", "" + value).message()); PlayerExperienceGainEvent event = new PlayerExperienceGainEvent(playerData, profession, (int) value, source); @@ -166,13 +190,17 @@ public class PlayerProfessions { playerData.giveExperience((int) profession.getExperience().calculate(level), null); } - if (check && playerData.isOnline()) { + if (check) { Bukkit.getPluginManager().callEvent(new PlayerLevelUpEvent(playerData, profession, oldLevel, level)); new SmallParticleEffect(playerData.getPlayer(), Particle.SPELL_INSTANT); new ConfigMessage("profession-level-up").addPlaceholders("level", "" + level, "profession", profession.getName()) .send(playerData.getPlayer()); MMOCore.plugin.soundManager.play(playerData.getPlayer(), SoundManager.SoundEvent.LEVEL_UP); playerData.getStats().updateStats(); + + // Apply profession experience table + if (profession.hasExperienceTable()) + profession.getExperienceTable().claim(playerData, level, this); } StringBuilder bar = new StringBuilder("" + ChatColor.BOLD); @@ -183,4 +211,20 @@ public class PlayerProfessions { MMOCore.plugin.configManager.getSimpleMessage("exp-notification", "profession", profession.getName(), "progress", bar.toString(), "ratio", MythicLib.plugin.getMMOConfig().decimal.format((double) exp / needed * 100)).send(playerData.getPlayer()); } + + /** + * @return The amount of times that specific experience item was claimed by the player + */ + public int getTimesClaimed(ExperienceTable table, ExperienceItem item) { + String path = table.getId() + "." + item.getId(); + return timesClaimed.getOrDefault(path, 0); + } + + /** + * See {@link #getTimesClaimed(ExperienceTable, ExperienceItem)} + */ + public void setTimesClaimed(ExperienceTable table, ExperienceItem item, int timesClaimed) { + String path = table.getId() + "." + item.getId(); + this.timesClaimed.put(path, timesClaimed); + } } diff --git a/src/main/java/net/Indyuce/mmocore/experience/Profession.java b/src/main/java/net/Indyuce/mmocore/experience/Profession.java index 3c939d84..d7d431d7 100644 --- a/src/main/java/net/Indyuce/mmocore/experience/Profession.java +++ b/src/main/java/net/Indyuce/mmocore/experience/Profession.java @@ -1,48 +1,55 @@ package net.Indyuce.mmocore.experience; -import io.lumine.mythic.lib.MythicLib; import io.lumine.mythic.lib.api.MMOLineConfig; import io.lumine.mythic.lib.api.util.PostLoadObject; import net.Indyuce.mmocore.MMOCore; import net.Indyuce.mmocore.api.util.math.formula.LinearValue; +import net.Indyuce.mmocore.experience.droptable.ExperienceTable; import net.Indyuce.mmocore.experience.provider.ExperienceDispenser; import net.Indyuce.mmocore.experience.provider.ProfessionExperienceDispenser; import org.apache.commons.lang.Validate; -import org.bukkit.Material; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.file.FileConfiguration; -import org.bukkit.enchantments.Enchantment; -import org.bukkit.potion.PotionType; import java.util.HashMap; import java.util.Map; import java.util.Objects; import java.util.logging.Level; -public class Profession extends PostLoadObject { +public class Profession { private final String id, name; private final ExpCurve expCurve; private final int maxLevel; private final Map options = new HashMap<>(); + private final ExperienceTable expTable; - /* - * experience given to the main player level whenever he levels up this - * profession + /** + * Experience given to the main player level whenever he levels up this profession + * + * @deprecated Being replaced by {@link ExperienceTable} */ + @Deprecated private final LinearValue experience; public Profession(String id, FileConfiguration config) { - super(config); - this.id = id.toLowerCase().replace("_", "-").replace(" ", "-"); this.name = config.getString("name"); Validate.notNull(name, "Could not load name"); expCurve = config.contains("exp-curve") - ? MMOCore.plugin.experience.getOrThrow(config.get("exp-curve").toString().toLowerCase().replace("_", "-").replace(" ", "-")) + ? MMOCore.plugin.experience.getCurveOrThrow(config.get("exp-curve").toString().toLowerCase().replace("_", "-").replace(" ", "-")) : ExpCurve.DEFAULT; experience = new LinearValue(config.getConfigurationSection("experience")); + ExperienceTable expTable = null; + if (config.contains("exp-table")) + try { + expTable = loadExperienceTable(config.get("exp-table")); + } catch (RuntimeException exception) { + MMOCore.plugin.getLogger().log(Level.WARNING, "Could not load exp table from profession '" + id + "': " + exception.getMessage()); + } + this.expTable = expTable; + if (config.contains("options")) for (String key : config.getConfigurationSection("options").getKeys(false)) try { @@ -59,71 +66,25 @@ public class Profession extends PostLoadObject { ExperienceDispenser dispenser = new ProfessionExperienceDispenser(this); for (String key : config.getStringList("exp-sources")) try { - MMOCore.plugin.professionManager.registerExpSource(MMOCore.plugin.loadManager.loadExperienceSource(new MMOLineConfig(key), dispenser)); + MMOCore.plugin.experience.registerSource(MMOCore.plugin.loadManager.loadExperienceSource(new MMOLineConfig(key), dispenser)); } catch (IllegalArgumentException exception) { MMOCore.plugin.getLogger().log(Level.WARNING, "Could not register exp source '" + key + "' from profession '" + id + "': " + exception.getMessage()); } } + + MMOCore.plugin.professionManager.loadProfessionConfigurations(config); } - /* - * drop tables must be loaded after professions are initialized - */ - @Override - protected void whenPostLoaded(ConfigurationSection config) { + private ExperienceTable loadExperienceTable(Object obj) { - if (config.contains("on-fish")) - MMOCore.plugin.fishingManager.loadDropTables(config.getConfigurationSection("on-fish")); + if (obj instanceof ConfigurationSection) + return new ExperienceTable((ConfigurationSection) obj); - if (config.contains("on-mine")) - MMOCore.plugin.mineManager.loadDropTables(config.getConfigurationSection("on-mine")); + if (obj instanceof String) + return MMOCore.plugin.experience.getTableOrThrow(obj.toString()); - if (config.contains("alchemy-experience")) { - - MMOCore.plugin.alchemyManager.splash = 1 + config.getDouble("alchemy-experience.special.splash") / 100; - MMOCore.plugin.alchemyManager.lingering = 1 + config.getDouble("alchemy-experience.special.lingering") / 100; - MMOCore.plugin.alchemyManager.extend = 1 + config.getDouble("alchemy-experience.special.extend") / 100; - MMOCore.plugin.alchemyManager.upgrade = 1 + config.getDouble("alchemy-experience.special.upgrade") / 100; - - for (String key : config.getConfigurationSection("alchemy-experience.effects").getKeys(false)) - try { - PotionType type = PotionType.valueOf(key.toUpperCase().replace("-", "_").replace(" ", "_")); - MMOCore.plugin.alchemyManager.registerBaseExperience(type, config.getDouble("alchemy-experience.effects." + key)); - } catch (IllegalArgumentException exception) { - MMOCore.log(Level.WARNING, "[PlayerProfessions:" + id + "] Could not read potion type from " + key); - } - } - - if (config.contains("base-enchant-exp")) - for (String key : config.getConfigurationSection("base-enchant-exp").getKeys(false)) - try { - Enchantment enchant = MythicLib.plugin.getVersion().getWrapper().getEnchantmentFromString(key.toLowerCase().replace("-", "_")); - MMOCore.plugin.enchantManager.registerBaseExperience(enchant, config.getDouble("base-enchant-exp." + key)); - } catch (IllegalArgumentException exception) { - MMOCore.log(Level.WARNING, "[PlayerProfessions:" + id + "] Could not read enchant from " + key); - } - - if (config.contains("repair-exp")) - for (String key : config.getConfigurationSection("repair-exp").getKeys(false)) - try { - Material material = Material.valueOf(key.toUpperCase().replace("-", "_").replace(" ", "_")); - MMOCore.plugin.smithingManager.registerBaseExperience(material, config.getDouble("repair-exp." + key)); - } catch (IllegalArgumentException exception) { - MMOCore.log(Level.WARNING, "[PlayerProfessions:" + id + "] Could not read material from " + key); - } - - // if (config.contains("effect-weight")) - // for (String key : - // config.getConfigurationSection("effect-weight").getKeys(false)) - // try { - // MMOCore.plugin.alchemyManager.registerEffectWeight(PotionEffectType.getByName(key.toUpperCase().replace("-", - // "_").replace(" ", "_")), config.getDouble("effect-weight." + key)); - // } catch (IllegalArgumentException exception) { - // MMOCore.log(Level.WARNING, "[PlayerProfessions:" + id + "] Could not - // read - // potion effect type from " + key); - // } + throw new IllegalArgumentException("Please provide either a string (exp table name) or a config section (locally define an exp table)"); } public boolean getOption(ProfessionOption option) { @@ -158,6 +119,14 @@ public class Profession extends PostLoadObject { return experience; } + public boolean hasExperienceTable() { + return expTable != null; + } + + public ExperienceTable getExperienceTable() { + return Objects.requireNonNull(expTable, "Profession has no exp table"); + } + public static enum ProfessionOption { /** diff --git a/src/main/java/net/Indyuce/mmocore/experience/droptable/ExperienceItem.java b/src/main/java/net/Indyuce/mmocore/experience/droptable/ExperienceItem.java new file mode 100644 index 00000000..e676156b --- /dev/null +++ b/src/main/java/net/Indyuce/mmocore/experience/droptable/ExperienceItem.java @@ -0,0 +1,79 @@ +package net.Indyuce.mmocore.experience.droptable; + +import io.lumine.mythic.lib.api.MMOLineConfig; +import net.Indyuce.mmocore.MMOCore; +import net.Indyuce.mmocore.api.player.PlayerData; +import net.Indyuce.mmocore.api.quest.trigger.Trigger; +import org.apache.commons.lang.Validate; +import org.bukkit.configuration.ConfigurationSection; + +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +public class ExperienceItem { + private final String id; + private final int period; + private final double claimChance, failReduction; + private final List triggers; + + private static final Random random = new Random(); + + /** + * One item for an experience table + * + * @param period The experience item is claimed every X level ups + * @param claimChance Chance for that item to be claimed every X level ups + * @param failReduction Between 0 and 1, by how much the fail chance is reduced + * every time the item is not claimed when leveling up. + *

+ * Failing chance follows a geometric sequence therefore + * successChance = 1 - (1 - initialSuccessChance) * failReduction^n + * where n is the amount of successive claiming fails + * @param triggers Actions cast when the exp item is claimed + */ + public ExperienceItem(String id, int period, double claimChance, double failReduction, List triggers) { + this.id = id; + this.period = period; + this.claimChance = claimChance; + this.failReduction = failReduction; + this.triggers = triggers; + } + + public ExperienceItem(ConfigurationSection config) { + Validate.notNull(config, "Config cannot be null"); + Validate.isTrue(config.contains("triggers")); + id = config.getName(); + period = config.getInt("period", 1); + claimChance = config.getDouble("chance", 100) / 100; + failReduction = config.getDouble("fail-reduction", 80) / 100; + triggers = new ArrayList<>(); + + for (String triggerFormat : config.getStringList("triggers")) + triggers.add(MMOCore.plugin.loadManager.loadTrigger(new MMOLineConfig(triggerFormat))); + } + + public String getId() { + return id; + } + + /** + * @param professionLevel The profession level the player just reached + * @param timesCollected Amount of times the exp item has already been claimed by the player + * @return If the item should be claimed right now taking into + * account the randomness factor from the 'chance' parameter + */ + public boolean roll(int professionLevel, int timesCollected) { + int claimsRequired = professionLevel - (timesCollected + 1) * period; + if (claimsRequired < 1) + return false; + + double chance = 1 - (1 - claimChance) * Math.pow(failReduction, claimsRequired); + return random.nextDouble() < chance; + } + + public void applyTriggers(PlayerData levelingUp) { + for (Trigger trigger : triggers) + trigger.apply(levelingUp); + } +} diff --git a/src/main/java/net/Indyuce/mmocore/experience/droptable/ExperienceTable.java b/src/main/java/net/Indyuce/mmocore/experience/droptable/ExperienceTable.java new file mode 100644 index 00000000..9501bea0 --- /dev/null +++ b/src/main/java/net/Indyuce/mmocore/experience/droptable/ExperienceTable.java @@ -0,0 +1,55 @@ +package net.Indyuce.mmocore.experience.droptable; + +import net.Indyuce.mmocore.MMOCore; +import net.Indyuce.mmocore.api.player.PlayerData; +import net.Indyuce.mmocore.experience.PlayerProfessions; +import org.apache.commons.lang.Validate; +import org.bukkit.configuration.ConfigurationSection; + +import java.util.ArrayList; +import java.util.List; +import java.util.logging.Level; + +public class ExperienceTable { + private final String id; + private final List items = new ArrayList<>(); + + public ExperienceTable(ConfigurationSection config) { + Validate.notNull(config, "Config cannot be null"); + id = config.getName(); + + for (String str : config.getKeys(false)) + try { + Validate.isTrue(config.isConfigurationSection(str), "Key '" + str + "' is not a configuration section"); + items.add(new ExperienceItem(config.getConfigurationSection(str))); + } catch (RuntimeException exception) { + MMOCore.plugin.getLogger().log(Level.WARNING, "Could not load item '" + str + "' from experience table '" + id + "': " + exception.getMessage()); + } + } + + public String getId() { + return id; + } + + public List getItems() { + return items; + } + + /** + * Called when a player levels up one of his professions + * + * @param levelingUp Player leveling up + * @param professionLevel New profession level + * @param professionData Player profession data + */ + public void claim(PlayerData levelingUp, int professionLevel, PlayerProfessions professionData) { + for (ExperienceItem item : items) { + int timesClaimed = professionData.getTimesClaimed(this, item); + if (!item.roll(professionLevel, timesClaimed)) + continue; + + professionData.setTimesClaimed(this, item, timesClaimed + 1); + item.applyTriggers(levelingUp); + } + } +} diff --git a/src/main/java/net/Indyuce/mmocore/manager/ConfigManager.java b/src/main/java/net/Indyuce/mmocore/manager/ConfigManager.java index b069c7f1..abb187d7 100644 --- a/src/main/java/net/Indyuce/mmocore/manager/ConfigManager.java +++ b/src/main/java/net/Indyuce/mmocore/manager/ConfigManager.java @@ -86,6 +86,7 @@ public class ConfigManager { loadDefaultFile("sounds.yml"); loadDefaultFile("loot-chests.yml"); loadDefaultFile("commands.yml"); + loadDefaultFile("exp-tables.yml"); loadDefaultFile("guilds.yml"); commandVerbose.reload(MMOCore.plugin.getConfig().getConfigurationSection("command-verbose")); diff --git a/src/main/java/net/Indyuce/mmocore/manager/ExperienceManager.java b/src/main/java/net/Indyuce/mmocore/manager/ExperienceManager.java index 9fbed0a9..c52a56a7 100644 --- a/src/main/java/net/Indyuce/mmocore/manager/ExperienceManager.java +++ b/src/main/java/net/Indyuce/mmocore/manager/ExperienceManager.java @@ -1,45 +1,98 @@ package net.Indyuce.mmocore.manager; +import net.Indyuce.mmocore.MMOCore; +import net.Indyuce.mmocore.api.ConfigFile; +import net.Indyuce.mmocore.experience.ExpCurve; +import net.Indyuce.mmocore.experience.droptable.ExperienceTable; +import net.Indyuce.mmocore.experience.source.type.ExperienceSource; +import net.Indyuce.mmocore.manager.profession.ExperienceSourceManager; +import org.apache.commons.lang.Validate; +import org.bukkit.configuration.file.FileConfiguration; +import org.bukkit.event.HandlerList; + import java.io.File; import java.io.IOException; import java.util.Collection; import java.util.HashMap; import java.util.Map; +import java.util.Objects; import java.util.logging.Level; -import org.apache.commons.lang.Validate; +public class ExperienceManager implements MMOCoreManager { + private final Map expCurves = new HashMap<>(); + private final Map expTables = new HashMap<>(); -import net.Indyuce.mmocore.MMOCore; -import net.Indyuce.mmocore.experience.ExpCurve; + /** + * Saves different experience sources based on experience source type. + */ + private final Map, ExperienceSourceManager> managers = new HashMap<>(); -public class ExperienceManager { - private final Map expCurves = new HashMap<>(); + @SuppressWarnings("unchecked") + public ExperienceSourceManager getManager(Class t) { + return (ExperienceSourceManager) managers.get(t); + } - public boolean hasCurve(String id) { - return expCurves.containsKey(id); - } + @SuppressWarnings("unchecked") + public void registerSource(T source) { + Class path = (Class) source.getClass(); - public ExpCurve getOrThrow(String id) { - Validate.isTrue(hasCurve(id), "Could not find exp curve with ID '" + id + "'"); - return expCurves.get(id); - } + if (!managers.containsKey(path)) + managers.put(path, source.newManager()); + getManager(path).registerSource(source); + } - public ExpCurve getCurve(String id) { - return expCurves.get(id); - } + public boolean hasCurve(String id) { + return expCurves.containsKey(id); + } - public Collection getCurves() { - return expCurves.values(); - } + public ExpCurve getCurveOrThrow(String id) { + Validate.isTrue(hasCurve(id), "Could not find exp curve with ID '" + id + "'"); + return expCurves.get(id); + } - public void reload() { - expCurves.clear(); - for (File file : new File(MMOCore.plugin.getDataFolder() + "/expcurves").listFiles()) - try { - ExpCurve curve = new ExpCurve(file); - expCurves.put(curve.getId(), curve); - } catch (IllegalArgumentException | IOException exception) { - MMOCore.plugin.getLogger().log(Level.WARNING, "Could not load exp curve '" + file.getName() + "': " + exception.getMessage()); - } - } + public boolean hasTable(String id) { + return expTables.containsKey(id); + } + + public ExperienceTable getTableOrThrow(String id) { + return Objects.requireNonNull(expTables.get(id), "Could not find exp table with ID '" + id + "'"); + } + + public Collection getCurves() { + return expCurves.values(); + } + + public Collection getTables() { + return expTables.values(); + } + + @Override + public void initialize(boolean clearBefore) { + if (clearBefore) { + expCurves.clear(); + expTables.clear(); + + managers.values().forEach(HandlerList::unregisterAll); + managers.clear(); + } + + expCurves.clear(); + for (File file : new File(MMOCore.plugin.getDataFolder() + "/expcurves").listFiles()) + try { + ExpCurve curve = new ExpCurve(file); + expCurves.put(curve.getId(), curve); + } catch (IllegalArgumentException | IOException exception) { + MMOCore.plugin.getLogger().log(Level.WARNING, "Could not load exp curve '" + file.getName() + "': " + exception.getMessage()); + } + + expTables.clear(); + FileConfiguration expTablesConfig = new ConfigFile("exp-tables").getConfig(); + for (String key : expTablesConfig.getKeys(false)) + try { + ExperienceTable table = new ExperienceTable(expTablesConfig.getConfigurationSection(key)); + expTables.put(table.getId(), table); + } catch (RuntimeException exception) { + MMOCore.plugin.getLogger().log(Level.WARNING, "Could not load exp table '" + key + "': " + exception.getMessage()); + } + } } diff --git a/src/main/java/net/Indyuce/mmocore/manager/MMOCoreManager.java b/src/main/java/net/Indyuce/mmocore/manager/MMOCoreManager.java new file mode 100644 index 00000000..5c7e9d7d --- /dev/null +++ b/src/main/java/net/Indyuce/mmocore/manager/MMOCoreManager.java @@ -0,0 +1,13 @@ +package net.Indyuce.mmocore.manager; + +public interface MMOCoreManager { + + /** + * Called either when the server starts when initializing the manager for + * the first time, or when issuing a plugin reload; in that case, stuff + * like listeners must all be cleared before + * + * @param clearBefore True when issuing a plugin reload + */ + void initialize(boolean clearBefore); +} diff --git a/src/main/resources/default/exp-tables.yml b/src/main/resources/default/exp-tables.yml new file mode 100644 index 00000000..842f8d10 --- /dev/null +++ b/src/main/resources/default/exp-tables.yml @@ -0,0 +1,46 @@ +example_exp_table: + first_table_item: + + # This item will drop every 3 level ups + period: 3 + + # This item has a 80% chance to drop every 3 level ups + chance: 80 + + # Every successive fail in claiming the item will reduce + # the risk of failing future claims by X%. With a 80% + # fail reduction rate, chances become: + # - 80% + # - 96% + # - 99.2% + # - 99.84% + # so on forever.. + # + # This is better than just increasing the claim chance by a + # certain amount each time because otherwise the claim chance + # just becomes/surpasses 100% at some point. + fail-reduction: 80 + + # What happens when that item is claimed + triggers: + - 'exp{amount=20}' + + second_table_item: + period: 2 + triggers: + - 'exp{amount=80}' + - 'command{format="broadcast Boy, %player_name% level up twice in one of his(her) professions!"}' + +second_exp_table: + + # Base exp every level up, sweet. + some_item: + period: 1 + triggers: + - 'exp{amount=100}' + + # Extra exp every 3 levels + some_other_item: + period: 3 + triggers: + - 'exp{amount=100}' \ No newline at end of file