Merge remote-tracking branch 'origin/master'

# Conflicts:
#	src/main/java/net/Indyuce/mmocore/api/player/profess/PlayerClass.java
#	src/main/java/net/Indyuce/mmocore/api/quest/trigger/ExperienceTrigger.java
#	src/main/java/net/Indyuce/mmocore/experience/ExperienceObject.java
#	src/main/java/net/Indyuce/mmocore/experience/Profession.java
#	src/main/java/net/Indyuce/mmocore/experience/SimpleExperienceObject.java
This commit is contained in:
Jules 2022-06-12 16:57:04 +02:00
commit 026d0194ea
121 changed files with 2913 additions and 1147 deletions

36
pom.xml
View File

@ -4,7 +4,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>net.Indyuce</groupId>
<artifactId>MMOCore</artifactId>
<version>1.9.2</version>
<version>1.9.3</version>
<name>MMOCore</name>
<description>Offer your players a brand new RPG experience!!</description>
@ -39,10 +39,17 @@
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.3.1</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>9</source>
<target>9</target>
@ -215,6 +222,33 @@
<scope>provided</scope>
</dependency>
<!--Quest Plugin-->
<dependency>
<groupId>me.blackvein</groupId>
<artifactId>Quests</artifactId>
<version>4.4.1-b340</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>fr.skytasul.quests</groupId>
<artifactId>BeautyQuests</artifactId>
<version>0.19.5</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.guillaumevdn</groupId>
<artifactId>QuestCreator</artifactId>
<version>6.39.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.guillaumevdn</groupId>
<artifactId>GCore</artifactId>
<version>8.39.0</version>
<scope>provided</scope>
</dependency>
<!-- Guild plugins -->
<dependency>
<groupId>com.massivecraft</groupId>

View File

@ -8,11 +8,10 @@ import io.lumine.mythic.utils.plugin.LuminePlugin;
import net.Indyuce.mmocore.api.ConfigFile;
import net.Indyuce.mmocore.api.PlayerActionBar;
import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.api.player.attribute.AttributeModifier;
import net.Indyuce.mmocore.api.player.profess.resource.PlayerResource;
import net.Indyuce.mmocore.api.player.stats.StatType;
import net.Indyuce.mmocore.api.util.debug.DebugMode;
import net.Indyuce.mmocore.command.*;
import net.Indyuce.mmocore.comp.MMOCoreTargetRestriction;
import net.Indyuce.mmocore.comp.citizens.CitizenInteractEventListener;
import net.Indyuce.mmocore.comp.citizens.CitizensMMOLoader;
import net.Indyuce.mmocore.comp.mythicmobs.MythicHook;
@ -32,7 +31,6 @@ import net.Indyuce.mmocore.listener.event.PlayerPressKeyListener;
import net.Indyuce.mmocore.listener.option.*;
import net.Indyuce.mmocore.listener.profession.FishingListener;
import net.Indyuce.mmocore.listener.profession.PlayerCollectStats;
import net.Indyuce.mmocore.loot.chest.LootChest;
import net.Indyuce.mmocore.manager.*;
import net.Indyuce.mmocore.manager.data.DataProvider;
import net.Indyuce.mmocore.manager.data.mysql.MySQLDataProvider;
@ -41,6 +39,7 @@ import net.Indyuce.mmocore.manager.profession.*;
import net.Indyuce.mmocore.manager.social.BoosterManager;
import net.Indyuce.mmocore.manager.social.PartyManager;
import net.Indyuce.mmocore.manager.social.RequestManager;
import net.Indyuce.mmocore.party.MMOCoreTargetRestriction;
import net.Indyuce.mmocore.party.PartyModule;
import net.Indyuce.mmocore.party.PartyModuleType;
import net.Indyuce.mmocore.party.provided.MMOCorePartyModule;
@ -55,7 +54,6 @@ import org.jetbrains.annotations.NotNull;
import java.io.File;
import java.lang.reflect.Field;
import java.util.Iterator;
import java.util.logging.Level;
public class MMOCore extends LuminePlugin {
@ -78,6 +76,7 @@ public class MMOCore extends LuminePlugin {
public final LootChestManager lootChests = new LootChestManager();
public final MMOLoadManager loadManager = new MMOLoadManager();
public final RestrictionManager restrictionManager = new RestrictionManager();
public final StatManager statManager = new StatManager();
@Deprecated
public final SkillTreeManager skillTreeManager = new SkillTreeManager();
@ -116,8 +115,10 @@ public class MMOCore extends LuminePlugin {
return;
}
// Register target restrictions due to MMOCore in MythicLib
// Register MMOCore-specific objects
MythicLib.plugin.getEntities().registerRestriction(new MMOCoreTargetRestriction());
MythicLib.plugin.getModifiers().registerModifierType("attribute", configObject -> new AttributeModifier(configObject));
// Register extra objective, drop items...
if (Bukkit.getPluginManager().getPlugin("WorldGuard") != null)
@ -189,23 +190,6 @@ public class MMOCore extends LuminePlugin {
}
}.runTaskTimer(MMOCore.plugin, 100, 20);
/*
* Clean active loot chests every 5 minutes. Cannot register this runnable in
* the loot chest manager because it is instanced when the plugin loads
*/
new BukkitRunnable() {
public void run() {
Iterator<LootChest> iterator = lootChests.getActive().iterator();
while (iterator.hasNext()) {
LootChest next = iterator.next();
if (next.shouldExpire()) {
iterator.remove();
next.expire(false);
}
}
}
}.runTaskTimer(this, 5 * 60 * 20, 5 * 60 * 20);
/*
* For the sake of the lord, make sure they aren't using MMOItems Mana and
* Stamina Addon...This should prevent a couple error reports produced by people
@ -230,6 +214,19 @@ public class MMOCore extends LuminePlugin {
DebugMode.enableActionBar();
}
// Load quest module
try {
String questPluginName = UtilityMethods.enumName(getConfig().getString("quest-plugin"));
PartyModuleType moduleType = PartyModuleType.valueOf(questPluginName);
Validate.isTrue(moduleType.isValid(), "Plugin '" + moduleType.name() + "' is not installed");
partyModule = moduleType.provideModule();
} catch (RuntimeException exception) {
getLogger().log(Level.WARNING, "Could not initialize quest module: " + exception.getMessage());
partyModule = new MMOCorePartyModule();
}
// Load party module
try {
String partyPluginName = UtilityMethods.enumName(getConfig().getString("party-plugin"));
@ -241,6 +238,7 @@ public class MMOCore extends LuminePlugin {
partyModule = new MMOCorePartyModule();
}
// Skill casting
try {
SkillCastingMode mode = SkillCastingMode.valueOf(UtilityMethods.enumName(getConfig().getString("skill-casting.mode")));
@ -388,6 +386,7 @@ public class MMOCore extends LuminePlugin {
configManager = new ConfigManager();
statManager.initialize(clearBefore);
if (clearBefore)
MythicLib.plugin.getSkills().initialize(true);
skillManager.initialize(clearBefore);
@ -417,8 +416,6 @@ public class MMOCore extends LuminePlugin {
if (getConfig().isConfigurationSection("action-bar"))
actionBarManager.reload(getConfig().getConfigurationSection("action-bar"));
StatType.load();
if (clearBefore)
PlayerData.getAll().forEach(PlayerData::update);
}

View File

@ -1,73 +1,72 @@
package net.Indyuce.mmocore.api;
import java.text.DecimalFormat;
import io.lumine.mythic.lib.MythicLib;
import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.player.PlayerActivity;
import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.player.stats.StatInfo;
import net.md_5.bungee.api.ChatMessageType;
import net.md_5.bungee.api.chat.TextComponent;
import org.bukkit.attribute.Attribute;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.scheduler.BukkitRunnable;
import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.api.player.stats.StatType;
import net.md_5.bungee.api.ChatMessageType;
import net.md_5.bungee.api.chat.TextComponent;
import io.lumine.mythic.lib.MythicLib;
import java.text.DecimalFormat;
public class PlayerActionBar extends BukkitRunnable {
boolean initialized = false;
private ActionBarConfig config;
private DecimalFormat digit;
public void reload(ConfigurationSection cfg) {
config = new ActionBarConfig(cfg);
digit = MythicLib.plugin.getMMOConfig().newDecimalFormat(config.digit);
boolean initialized = false;
if(!initialized && config.enabled) {
runTaskTimer(MMOCore.plugin, 0, config.ticks);
initialized = true;
}
}
public long getTimeOut() {
return config.timeout;
}
private ActionBarConfig config;
private DecimalFormat digit;
@Override
public void run() {
for (PlayerData data : PlayerData.getAll())
if (data.isOnline() && !data.getPlayer().isDead() && !data.isCasting() && data.getActivityTimeOut(PlayerActivity.ACTION_BAR_MESSAGE) == 0) {
data.getPlayer().spigot().sendMessage(ChatMessageType.ACTION_BAR, TextComponent.fromLegacyText(MMOCore.plugin.placeholderParser.parse(data.getPlayer(),
MythicLib.plugin.parseColors((data.getProfess().hasActionBar() ? data.getProfess().getActionBar() : config.format)
.replace("{health}", digit.format(data.getPlayer().getHealth()))
.replace("{max_health}", "" + StatType.MAX_HEALTH.format(data.getPlayer().getAttribute(Attribute.GENERIC_MAX_HEALTH).getValue()))
.replace("{mana_icon}", data.getProfess().getManaDisplay().getIcon())
.replace("{mana}", digit.format(data.getMana()))
.replace("{max_mana}", "" + StatType.MAX_MANA.format(data.getStats().getStat(StatType.MAX_MANA)))
.replace("{stamina}", digit.format(data.getStamina()))
.replace("{max_stamina}", "" + StatType.MAX_STAMINA.format(data.getStats().getStat(StatType.MAX_STAMINA)))
.replace("{stellium}", digit.format(data.getStellium()))
.replace("{max_stellium}", "" + StatType.MAX_STELLIUM.format(data.getStats().getStat(StatType.MAX_STELLIUM)))
.replace("{class}", data.getProfess().getName())
.replace("{xp}", "" + data.getExperience())
.replace("{armor}", "" + StatType.ARMOR.format(data.getPlayer().getAttribute(Attribute.GENERIC_ARMOR).getValue()))
.replace("{level}", "" + data.getLevel())
.replace("{name}", data.getPlayer().getDisplayName())))));
}
}
private static class ActionBarConfig {
private final boolean enabled;
private final int ticks, timeout;
private final String digit, format;
private ActionBarConfig(ConfigurationSection config) {
enabled = config.getBoolean("enabled", false);
timeout = config.getInt("", 60);
digit = config.getString("decimal", "0.#");
ticks = config.getInt("ticks-to-update", 5);
format = config.getString("format", "please format me :c");
}
}
public void reload(ConfigurationSection cfg) {
config = new ActionBarConfig(cfg);
digit = MythicLib.plugin.getMMOConfig().newDecimalFormat(config.digit);
if (!initialized && config.enabled) {
runTaskTimer(MMOCore.plugin, 0, config.ticks);
initialized = true;
}
}
public long getTimeOut() {
return config.timeout;
}
@Override
public void run() {
for (PlayerData data : PlayerData.getAll())
if (data.isOnline() && !data.getPlayer().isDead() && !data.isCasting() && data.getActivityTimeOut(PlayerActivity.ACTION_BAR_MESSAGE) == 0) {
data.getPlayer().spigot().sendMessage(ChatMessageType.ACTION_BAR, TextComponent.fromLegacyText(MMOCore.plugin.placeholderParser.parse(data.getPlayer(),
MythicLib.plugin.parseColors((data.getProfess().hasActionBar() ? data.getProfess().getActionBar() : config.format)
.replace("{health}", digit.format(data.getPlayer().getHealth()))
.replace("{max_health}", StatInfo.valueOf("MAX_HEALTH").format(data.getPlayer().getAttribute(Attribute.GENERIC_MAX_HEALTH).getValue()))
.replace("{mana_icon}", data.getProfess().getManaDisplay().getIcon())
.replace("{mana}", digit.format(data.getMana()))
.replace("{max_mana}", StatInfo.valueOf("MAX_MANA").format(data.getStats().getStat("MAX_MANA")))
.replace("{stamina}", digit.format(data.getStamina()))
.replace("{max_stamina}", StatInfo.valueOf("MAX_STAMINA").format(data.getStats().getStat("MAX_STAMINA")))
.replace("{stellium}", digit.format(data.getStellium()))
.replace("{max_stellium}", StatInfo.valueOf("MAX_STELLIUM").format(data.getStats().getStat("MAX_STELLIUM")))
.replace("{class}", data.getProfess().getName())
.replace("{xp}", "" + data.getExperience())
.replace("{armor}", StatInfo.valueOf("ARMOR").format(data.getPlayer().getAttribute(Attribute.GENERIC_ARMOR).getValue()))
.replace("{level}", "" + data.getLevel())
.replace("{name}", data.getPlayer().getDisplayName())))));
}
}
private static class ActionBarConfig {
private final boolean enabled;
private final int ticks, timeout;
private final String digit, format;
private ActionBarConfig(ConfigurationSection config) {
enabled = config.getBoolean("enabled", false);
timeout = config.getInt("", 60);
digit = config.getString("decimal", "0.#");
ticks = config.getInt("ticks-to-update", 5);
format = config.getString("format", "please format me :c");
}
}
}

View File

@ -16,14 +16,14 @@ public class PlayerExperienceGainEvent extends PlayerDataEvent implements Cancel
private final Profession profession;
private final EXPSource source;
private int experience;
private double experience;
private boolean cancelled;
public PlayerExperienceGainEvent(PlayerData player, int experience, EXPSource source) {
public PlayerExperienceGainEvent(PlayerData player, double experience, EXPSource source) {
this(player, null, experience, source);
}
public PlayerExperienceGainEvent(PlayerData player, @Nullable Profession profession, int experience, EXPSource source) {
public PlayerExperienceGainEvent(PlayerData player, @Nullable Profession profession, double experience, EXPSource source) {
super(player);
this.profession = profession;
@ -31,7 +31,7 @@ public class PlayerExperienceGainEvent extends PlayerDataEvent implements Cancel
this.source = source;
}
public int getExperience() {
public double getExperience() {
return experience;
}

View File

@ -1,30 +1,19 @@
package net.Indyuce.mmocore.api.load;
import net.Indyuce.mmocore.experience.dispenser.ExperienceDispenser;
import net.Indyuce.mmocore.experience.source.*;
import net.Indyuce.mmocore.loot.chest.condition.*;
import org.bukkit.configuration.ConfigurationSection;
import net.Indyuce.mmocore.api.block.BlockType;
import net.Indyuce.mmocore.api.block.SkullBlockType;
import net.Indyuce.mmocore.api.block.VanillaBlockType;
import net.Indyuce.mmocore.loot.droptable.condition.BiomeCondition;
import net.Indyuce.mmocore.loot.droptable.condition.Condition;
import net.Indyuce.mmocore.loot.droptable.condition.LevelCondition;
import net.Indyuce.mmocore.loot.droptable.condition.PermissionCondition;
import net.Indyuce.mmocore.loot.droptable.condition.WorldCondition;
import net.Indyuce.mmocore.loot.droptable.dropitem.DropItem;
import net.Indyuce.mmocore.loot.droptable.dropitem.DropTableDropItem;
import net.Indyuce.mmocore.loot.droptable.dropitem.GoldDropItem;
import net.Indyuce.mmocore.loot.droptable.dropitem.NoteDropItem;
import net.Indyuce.mmocore.loot.droptable.dropitem.VanillaDropItem;
import net.Indyuce.mmocore.experience.source.BrewPotionExperienceSource;
import net.Indyuce.mmocore.experience.source.CraftItemExperienceSource;
import net.Indyuce.mmocore.experience.source.EnchantItemExperienceSource;
import net.Indyuce.mmocore.experience.source.FishItemExperienceSource;
import net.Indyuce.mmocore.experience.source.KillMobExperienceSource;
import net.Indyuce.mmocore.experience.source.MineBlockExperienceSource;
import net.Indyuce.mmocore.experience.source.PlaceBlockExperienceSource;
import net.Indyuce.mmocore.experience.source.RepairItemExperienceSource;
import net.Indyuce.mmocore.experience.source.SmeltItemExperienceSource;
import net.Indyuce.mmocore.experience.source.type.ExperienceSource;
import net.Indyuce.mmocore.api.quest.objective.ClickonObjective;
import net.Indyuce.mmocore.api.quest.objective.GoToObjective;
@ -44,127 +33,154 @@ import io.lumine.mythic.lib.api.MMOLineConfig;
public class DefaultMMOLoader extends MMOLoader {
@Override
public Trigger loadTrigger(MMOLineConfig config) {
if (config.getKey().equals("message"))
return new MessageTrigger(config);
@Override
public Trigger loadTrigger(MMOLineConfig config) {
if (config.getKey().equals("message"))
return new MessageTrigger(config);
if (config.getKey().equals("sound") || config.getKey().equals("playsound"))
return new SoundTrigger(config);
if (config.getKey().equals("sound") || config.getKey().equals("playsound"))
return new SoundTrigger(config);
if (config.getKey().equals("mana"))
return new ManaTrigger(config);
if (config.getKey().equals("mana"))
return new ManaTrigger(config);
if (config.getKey().equals("stamina"))
return new StaminaTrigger(config);
if (config.getKey().equals("stellium"))
return new StelliumTrigger(config);
if (config.getKey().equals("stamina"))
return new StaminaTrigger(config);
if (config.getKey().equals("command"))
return new CommandTrigger(config);
if (config.getKey().equals("stellium"))
return new StelliumTrigger(config);
if (config.getKey().equals("item") || config.getKey().equals("vanilla"))
return new ItemTrigger(config);
if (config.getKey().equals("command"))
return new CommandTrigger(config);
if (config.getKey().equals("exp") || config.getKey().equals("experience"))
return new ExperienceTrigger(config);
if (config.getKey().equals("item") || config.getKey().equals("vanilla"))
return new ItemTrigger(config);
return null;
}
if (config.getKey().equals("exp") || config.getKey().equals("experience"))
return new ExperienceTrigger(config);
@Override
public DropItem loadDropItem(MMOLineConfig config) {
if (config.getKey().equals("droptable"))
return new DropTableDropItem(config);
return null;
}
if (config.getKey().equals("vanilla"))
return new VanillaDropItem(config);
@Override
public DropItem loadDropItem(MMOLineConfig config) {
if (config.getKey().equals("droptable"))
return new DropTableDropItem(config);
if (config.getKey().equals("note"))
return new NoteDropItem(config);
if (config.getKey().equals("vanilla"))
return new VanillaDropItem(config);
if (config.getKey().equals("gold") || config.getKey().equals("coin"))
return new GoldDropItem(config);
if (config.getKey().equals("note"))
return new NoteDropItem(config);
return null;
}
if (config.getKey().equals("gold") || config.getKey().equals("coin"))
return new GoldDropItem(config);
@Override
public Objective loadObjective(MMOLineConfig config, ConfigurationSection section) {
if (config.getKey().equals("goto"))
return new GoToObjective(section, config);
return null;
}
if (config.getKey().equals("mineblock"))
return new MineBlockObjective(section, config);
@Override
public Objective loadObjective(MMOLineConfig config, ConfigurationSection section) {
if (config.getKey().equals("goto"))
return new GoToObjective(section, config);
if (config.getKey().equals("killmob"))
return new KillMobObjective(section, config);
if (config.getKey().equals("mineblock"))
return new MineBlockObjective(section, config);
if (config.getKey().equals("clickon"))
return new ClickonObjective(section, config);
if (config.getKey().equals("killmob"))
return new KillMobObjective(section, config);
return null;
}
if (config.getKey().equals("clickon"))
return new ClickonObjective(section, config);
@Override
public Condition loadCondition(MMOLineConfig config) {
if (config.getKey().equals("world"))
return new WorldCondition(config);
return null;
}
if (config.getKey().equals("biome"))
return new BiomeCondition(config);
@Override
public Condition loadCondition(MMOLineConfig config) {
if (config.getKey().equals("distance"))
return new DistanceCondition(config);
if (config.getKey().equals("level"))
return new LevelCondition(config);
if (config.getKey().equals("permission"))
return new PermissionCondition(config);
if (config.getKey().equals("world"))
return new WorldCondition(config);
return null;
}
if (config.getKey().equals("biome"))
return new BiomeCondition(config);
@Override
public ExperienceSource<?> loadExperienceSource(MMOLineConfig config, ExperienceDispenser dispenser) {
if (config.getKey().equals("fishitem"))
return new FishItemExperienceSource(dispenser, config);
if (config.getKey().equals("level"))
return new LevelCondition(config);
if (config.getKey().equals("killmob"))
return new KillMobExperienceSource(dispenser, config);
if (config.getKey().equals("permission"))
return new PermissionCondition(config);
if (config.getKey().equals("mineblock"))
return new MineBlockExperienceSource(dispenser, config);
return null;
}
if (config.getKey().equals("placeblock"))
return new PlaceBlockExperienceSource(dispenser, config);
@Override
public ExperienceSource<?> loadExperienceSource(MMOLineConfig config, ExperienceDispenser dispenser) {
if (config.getKey().equals("resource"))
return new ResourceExperienceSource(dispenser, config);
if (config.getKey().equals("brewpotion"))
return new BrewPotionExperienceSource(dispenser, config);
if (config.getKey().equals("climb"))
return new ClimbExperienceSource(dispenser, config);
if (config.getKey().equals("smeltitem"))
return new SmeltItemExperienceSource(dispenser, config);
if (config.getKey().equals("damagedealt"))
return new DamageDealtExperienceSource(dispenser, config);
if (config.getKey().equals("enchantitem"))
return new EnchantItemExperienceSource(dispenser, config);
if (config.getKey().equals("damagetaken"))
return new DamageTakenExperienceSource(dispenser, config);
if (config.getKey().equals("repairitem"))
return new RepairItemExperienceSource(dispenser, config);
if (config.getKey().equals("move"))
return new MoveExperienceSource(dispenser, config);
if (config.getKey().equals("craftitem"))
return new CraftItemExperienceSource(dispenser, config);
if (config.getKey().equals("play"))
return new PlayExperienceSource(dispenser, config);
return null;
}
if (config.getKey().equals("projectile"))
return new ProjectileExperienceSource(dispenser, config);
@Override
public BlockType loadBlockType(MMOLineConfig config) {
if (config.getKey().equals("ride"))
return new RideExperienceSource(dispenser, config);
if (config.getKey().equalsIgnoreCase("vanilla"))
return new VanillaBlockType(config);
if (config.getKey().equalsIgnoreCase("skull") || config.getKey().equals("head") || config.getKey().equals("playerhead"))
return new SkullBlockType(config);
if (config.getKey().equals("tame"))
return new TameExperienceSource(dispenser, config);
return null;
}
if (config.getKey().equals("killmob"))
return new KillMobExperienceSource(dispenser, config);
if (config.getKey().equals("mineblock"))
return new MineBlockExperienceSource(dispenser, config);
if (config.getKey().equals("placeblock"))
return new PlaceBlockExperienceSource(dispenser, config);
if (config.getKey().equals("brewpotion"))
return new BrewPotionExperienceSource(dispenser, config);
if (config.getKey().equals("smeltitem"))
return new SmeltItemExperienceSource(dispenser, config);
if (config.getKey().equals("enchantitem"))
return new EnchantItemExperienceSource(dispenser, config);
if (config.getKey().equals("repairitem"))
return new RepairItemExperienceSource(dispenser, config);
if (config.getKey().equals("craftitem"))
return new CraftItemExperienceSource(dispenser, config);
return null;
}
@Override
public BlockType loadBlockType(MMOLineConfig config) {
if (config.getKey().equalsIgnoreCase("vanilla"))
return new VanillaBlockType(config);
if (config.getKey().equalsIgnoreCase("skull") || config.getKey().equals("head") || config.getKey().equals("playerhead"))
return new SkullBlockType(config);
return null;
}
}

View File

@ -2,7 +2,7 @@ package net.Indyuce.mmocore.api.load;
import io.lumine.mythic.lib.api.MMOLineConfig;
import net.Indyuce.mmocore.api.block.BlockType;
import net.Indyuce.mmocore.loot.droptable.condition.Condition;
import net.Indyuce.mmocore.loot.chest.condition.Condition;
import net.Indyuce.mmocore.loot.droptable.dropitem.DropItem;
import net.Indyuce.mmocore.experience.dispenser.ExperienceDispenser;
import net.Indyuce.mmocore.experience.source.type.ExperienceSource;

View File

@ -1,15 +1,11 @@
package net.Indyuce.mmocore.api.player;
import io.lumine.mythic.lib.MythicLib;
import io.lumine.mythic.lib.api.player.MMOPlayerData;
import io.lumine.mythic.lib.player.TemporaryPlayerData;
import io.lumine.mythic.lib.player.cooldown.CooldownMap;
import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.ConfigMessage;
import net.Indyuce.mmocore.api.SoundEvent;
import net.Indyuce.mmocore.player.Unlockable;
import net.Indyuce.mmocore.waypoint.CostType;
import net.Indyuce.mmocore.waypoint.Waypoint;
import net.Indyuce.mmocore.api.event.PlayerExperienceGainEvent;
import net.Indyuce.mmocore.api.event.PlayerLevelUpEvent;
import net.Indyuce.mmocore.api.event.PlayerResourceUpdateEvent;
@ -21,11 +17,9 @@ import net.Indyuce.mmocore.api.player.profess.Subclass;
import net.Indyuce.mmocore.api.player.profess.resource.PlayerResource;
import net.Indyuce.mmocore.api.player.social.FriendRequest;
import net.Indyuce.mmocore.api.player.stats.PlayerStats;
import net.Indyuce.mmocore.api.player.stats.StatType;
import net.Indyuce.mmocore.api.quest.PlayerQuests;
import net.Indyuce.mmocore.api.util.Closable;
import net.Indyuce.mmocore.api.util.MMOCoreUtils;
import net.Indyuce.mmocore.loot.chest.particle.SmallParticleEffect;
import net.Indyuce.mmocore.experience.EXPSource;
import net.Indyuce.mmocore.experience.ExperienceObject;
import net.Indyuce.mmocore.experience.ExperienceTableClaimer;
@ -33,11 +27,14 @@ import net.Indyuce.mmocore.experience.PlayerProfessions;
import net.Indyuce.mmocore.experience.droptable.ExperienceItem;
import net.Indyuce.mmocore.experience.droptable.ExperienceTable;
import net.Indyuce.mmocore.guild.provided.Guild;
import net.Indyuce.mmocore.loot.chest.particle.SmallParticleEffect;
import net.Indyuce.mmocore.party.AbstractParty;
import net.Indyuce.mmocore.party.provided.Party;
import net.Indyuce.mmocore.player.Unlockable;
import net.Indyuce.mmocore.skill.ClassSkill;
import net.Indyuce.mmocore.skill.RegisteredSkill;
import net.Indyuce.mmocore.skill.cast.SkillCastingHandler;
import net.Indyuce.mmocore.waypoint.Waypoint;
import net.Indyuce.mmocore.waypoint.WaypointOption;
import net.md_5.bungee.api.ChatMessageType;
import net.md_5.bungee.api.chat.TextComponent;
@ -70,7 +67,8 @@ public class PlayerData extends OfflinePlayerData implements Closable, Experienc
*/
@Nullable
private PlayerClass profess;
private int level, experience, classPoints, skillPoints, attributePoints, attributeReallocationPoints;// skillReallocationPoints,
private int level, classPoints, skillPoints, attributePoints, attributeReallocationPoints;// skillReallocationPoints,
private double experience;
private double mana, stamina, stellium;
private Guild guild;
private SkillCastingHandler skillCasting;
@ -88,8 +86,9 @@ public class PlayerData extends OfflinePlayerData implements Closable, Experienc
/**
* Saves all the items that have been unlocked so far by
* the player. This can be used by other plugins by
* implementing the {@link Unlockable} interface
* the player. This is used for:
* - waypoints
* - skills
*
* @see {@link Unlockable}
*/
@ -289,8 +288,11 @@ public class PlayerData extends OfflinePlayerData implements Closable, Experienc
return guild != null;
}
/**
* @return If the item is unlocked by the player
*/
public boolean hasUnlocked(Unlockable unlockable) {
throw new RuntimeException("Not implemented yet");
return unlockedItems.contains(unlockable.getUnlockNamespacedKey());
}
/**
@ -299,7 +301,7 @@ public class PlayerData extends OfflinePlayerData implements Closable, Experienc
* @return If the item was already unlocked when calling this method
*/
public boolean unlock(Unlockable unlockable) {
throw new RuntimeException("Not implemented yet");
return unlockedItems.add(unlockable.getUnlockNamespacedKey());
}
public void setLevel(int level) {
@ -320,7 +322,7 @@ public class PlayerData extends OfflinePlayerData implements Closable, Experienc
giveExperience(total, source);
}
public void setExperience(int value) {
public void setExperience(double value) {
experience = Math.max(0, value);
refreshVanillaExp();
}
@ -457,9 +459,9 @@ public class PlayerData extends OfflinePlayerData implements Closable, Experienc
* Teleports the player to a specific waypoint. This applies
* the stellium waypoint cost and plays the teleport animation.
*
* @param waypoint Target waypoint
* @param target Target waypoint
*/
public void warp(Waypoint waypoint, CostType costType) {
public void warp(Waypoint target, double cost) {
/*
* This cooldown is only used internally to make sure the player is not
@ -467,8 +469,6 @@ public class PlayerData extends OfflinePlayerData implements Closable, Experienc
* player waypoints data
*/
setLastActivity(PlayerActivity.USE_WAYPOINT);
final double cost = waypoint.getCost(costType);
giveStellium(-cost, PlayerResourceUpdateEvent.UpdateReason.USE_WAYPOINT);
new BukkitRunnable() {
@ -491,7 +491,7 @@ public class PlayerData extends OfflinePlayerData implements Closable, Experienc
MMOCore.plugin.configManager.getSimpleMessage("warping-comencing", "left", "" + ((120 - t) / 20)).send(getPlayer());
if (t++ >= 100) {
getPlayer().teleport(waypoint.getLocation());
getPlayer().teleport(target.getLocation());
getPlayer().addPotionEffect(new PotionEffect(PotionEffectType.BLINDNESS, 20, 1, false, false));
MMOCore.plugin.soundManager.getSound(SoundEvent.WARP_TELEPORT).playTo(getPlayer());
cancel();
@ -518,7 +518,7 @@ public class PlayerData extends OfflinePlayerData implements Closable, Experienc
* @param value Experience to give the player
* @param source How the player earned experience
*/
public void giveExperience(int value, EXPSource source) {
public void giveExperience(double value, EXPSource source) {
giveExperience(value, source, null, true);
}
@ -532,13 +532,16 @@ public class PlayerData extends OfflinePlayerData implements Closable, Experienc
* @param splitExp Should the exp be split among party members
*/
public void giveExperience(double value, EXPSource source, @Nullable Location hologramLocation, boolean splitExp) {
if (value <= 0)
return;
if (hasReachedMaxLevel()) {
setExperience(0);
return;
}
value = MMOCore.plugin.boosterManager.calculateExp(null, value);
value *= 1 + getStats().getStat(StatType.ADDITIONAL_EXPERIENCE) / 100;
value *= 1 + getStats().getStat("ADDITIONAL_EXPERIENCE") / 100;
// Splitting exp through party members
AbstractParty party = getParty();
@ -549,7 +552,7 @@ public class PlayerData extends OfflinePlayerData implements Closable, Experienc
member.giveExperience(value, EXPSource.PARTY_SHARING, null, false);
}
PlayerExperienceGainEvent event = new PlayerExperienceGainEvent(this, (int) value, source);
PlayerExperienceGainEvent event = new PlayerExperienceGainEvent(this, value, source);
Bukkit.getPluginManager().callEvent(event);
if (event.isCancelled())
return;
@ -590,7 +593,7 @@ public class PlayerData extends OfflinePlayerData implements Closable, Experienc
refreshVanillaExp();
}
public int getExperience() {
public double getExperience() {
return experience;
}
@ -611,7 +614,7 @@ public class PlayerData extends OfflinePlayerData implements Closable, Experienc
public void giveMana(double amount, PlayerResourceUpdateEvent.UpdateReason reason) {
// Avoid calling useless event
double max = getStats().getStat(StatType.MAX_MANA);
double max = getStats().getStat("MAX_MANA");
double newest = Math.max(0, Math.min(mana + amount, max));
if (mana == newest)
return;
@ -636,7 +639,7 @@ public class PlayerData extends OfflinePlayerData implements Closable, Experienc
public void giveStamina(double amount, PlayerResourceUpdateEvent.UpdateReason reason) {
// Avoid calling useless event
double max = getStats().getStat(StatType.MAX_STAMINA);
double max = getStats().getStat("MAX_STAMINA");
double newest = Math.max(0, Math.min(stamina + amount, max));
if (stamina == newest)
return;
@ -661,7 +664,7 @@ public class PlayerData extends OfflinePlayerData implements Closable, Experienc
public void giveStellium(double amount, PlayerResourceUpdateEvent.UpdateReason reason) {
// Avoid calling useless event
double max = getStats().getStat(StatType.MAX_STELLIUM);
double max = getStats().getStat("MAX_STELLIUM");
double newest = Math.max(0, Math.min(stellium + amount, max));
if (stellium == newest)
return;
@ -696,15 +699,15 @@ public class PlayerData extends OfflinePlayerData implements Closable, Experienc
}
public void setMana(double amount) {
mana = Math.max(0, Math.min(amount, getStats().getStat(StatType.MAX_MANA)));
mana = Math.max(0, Math.min(amount, getStats().getStat("MAX_MANA")));
}
public void setStamina(double amount) {
stamina = Math.max(0, Math.min(amount, getStats().getStat(StatType.MAX_STAMINA)));
stamina = Math.max(0, Math.min(amount, getStats().getStat("MAX_STAMINA")));
}
public void setStellium(double amount) {
stellium = Math.max(0, Math.min(amount, getStats().getStat(StatType.MAX_STELLIUM)));
stellium = Math.max(0, Math.min(amount, getStats().getStat("MAX_STELLIUM")));
}
public boolean isFullyLoaded() {

View File

@ -12,6 +12,7 @@ import net.Indyuce.mmocore.api.player.PlayerData;
import org.apache.commons.lang.Validate;
import java.text.DecimalFormat;
import java.util.Objects;
public class AttributeModifier extends PlayerModifier {
private final String attribute;
@ -74,9 +75,10 @@ public class AttributeModifier extends PlayerModifier {
public AttributeModifier(ConfigObject object) {
super(object.getString("key"), EquipmentSlot.OTHER, ModifierSource.OTHER);
String str = Objects.requireNonNull(object.getString("value"));
type = str.toCharArray()[str.length() - 1] == '%' ? ModifierType.RELATIVE : ModifierType.FLAT;
value = Double.parseDouble(type == ModifierType.RELATIVE ? str.substring(0, str.length() - 1) : str);
this.attribute = object.getString("attribute");
this.value = object.getDouble("value");
type = object.getBoolean("multiplicative", false) ? ModifierType.RELATIVE : ModifierType.FLAT;
}
public String getAttribute() {

View File

@ -3,57 +3,109 @@ package net.Indyuce.mmocore.api.player.attribute;
import io.lumine.mythic.lib.MythicLib;
import io.lumine.mythic.lib.api.stat.modifier.StatModifier;
import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.experience.EXPSource;
import net.Indyuce.mmocore.experience.ExpCurve;
import net.Indyuce.mmocore.experience.ExperienceObject;
import net.Indyuce.mmocore.experience.droptable.ExperienceTable;
import org.apache.commons.lang.Validate;
import org.bukkit.Location;
import org.bukkit.configuration.ConfigurationSection;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
import java.util.logging.Level;
public class PlayerAttribute {
private final String id, name;
private final int max;
public class PlayerAttribute implements ExperienceObject {
private final String id, name;
private final int max;
private final ExperienceTable expTable;
/**
* Used to store stats using StatType, but attributes also need to access
* non basic MMOCore stats hence the string maps keys
*/
private final Set<StatModifier> buffs = new HashSet<>();
/**
* All buffs granted by an attribute. These are normalized and
* must be multiplied by the player level first
*/
private final Set<StatModifier> buffs = new HashSet<>();
public PlayerAttribute(ConfigurationSection config) {
Validate.notNull(config, "Could not load config");
id = config.getName().toLowerCase().replace("_", "-").replace(" ", "-");
public PlayerAttribute(ConfigurationSection config) {
Validate.notNull(config, "Could not load config");
id = config.getName().toLowerCase().replace("_", "-").replace(" ", "-");
name = MythicLib.plugin.parseColors(config.getString("name", "Attribute"));
max = config.contains("max-points") ? Math.max(1, config.getInt("max-points")) : 0;
name = MythicLib.plugin.parseColors(config.getString("name", "Attribute"));
max = config.contains("max-points") ? Math.max(1, config.getInt("max-points")) : 0;
if (config.contains("buff"))
for (String key : config.getConfigurationSection("buff").getKeys(false))
try {
String stat = key.toUpperCase().replace("-", "_").replace(" ", "_");
buffs.add(new StatModifier("attribute." + id, stat, config.getString("buff." + key)));
} catch (IllegalArgumentException exception) {
MMOCore.log(Level.WARNING, "Could not load buff '" + key + "' from attribute '" + id + "': " + exception.getMessage());
}
}
if (config.contains("buff"))
for (String key : config.getConfigurationSection("buff").getKeys(false))
try {
String stat = key.toUpperCase().replace("-", "_").replace(" ", "_");
buffs.add(new StatModifier("attribute." + id, stat, config.getString("buff." + key)));
} catch (IllegalArgumentException exception) {
MMOCore.log(Level.WARNING, "Could not load buff '" + key + "' from attribute '" + id + "': " + exception.getMessage());
}
public String getId() {
return id;
}
// Load exp table
ExperienceTable expTable = null;
if (config.contains("exp-table"))
try {
expTable = MMOCore.plugin.experience.loadExperienceTable(config.get("exp-table"));
} catch (RuntimeException exception) {
MMOCore.plugin.getLogger().log(Level.WARNING, "Could not load exp table from class '" + id + "': " + exception.getMessage());
}
this.expTable = expTable;
}
public String getName() {
return name;
}
public String getId() {
return id;
}
public boolean hasMax() {
return max > 0;
}
public String getName() {
return name;
}
public int getMax() {
return max;
}
public boolean hasMax() {
return max > 0;
}
public Set<StatModifier> getBuffs() {
return buffs;
}
public int getMax() {
return max;
}
public Set<StatModifier> getBuffs() {
return buffs;
}
@Override
public String getKey() {
return "attribute:" + getId().replace("-", "_");
}
@NotNull
@Override
public ExperienceTable getExperienceTable() {
return Objects.requireNonNull(expTable);
}
@Override
public boolean hasExperienceTable() {
return expTable != null;
}
@Nullable
@Override
public ExpCurve getExpCurve() {
throw new RuntimeException("Attributes don't have experience");
}
@Override
public void giveExperience(PlayerData playerData, double experience, @Nullable Location hologramLocation, @NotNull EXPSource source) {
throw new RuntimeException("Attributes don't have experience");
}
@Override
public boolean shouldHandle(PlayerData playerData) {
throw new RuntimeException("Attributes don't have experience");
}
}

View File

@ -129,8 +129,17 @@ public class PlayerAttributes {
update();
}
/**
* Adds X points to the base of the player attribute AND applies
* the attribute experience table.
*
* @param value Amount of attribute points spent in the attribute
*/
public void addBase(int value) {
PlayerAttribute attribute = MMOCore.plugin.attributeManager.get(id);
setBase(spent + value);
if (attribute.hasExperienceTable())
attribute.getExperienceTable().claim(data, spent, attribute);
}
/*
@ -159,14 +168,14 @@ public class PlayerAttributes {
return map.get(key);
}
public void addModifier(String key, double value) {
addModifier(new AttributeModifier(key, id, value, ModifierType.FLAT, EquipmentSlot.OTHER, ModifierSource.OTHER));
public AttributeModifier addModifier(String key, double value) {
return addModifier(new AttributeModifier(key, id, value, ModifierType.FLAT, EquipmentSlot.OTHER, ModifierSource.OTHER));
}
public void addModifier(AttributeModifier modifier) {
map.put(modifier.getKey(), modifier);
public AttributeModifier addModifier(AttributeModifier modifier) {
AttributeModifier mod = map.put(modifier.getKey(), modifier);
update();
return mod;
}
public Set<String> getKeys() {
@ -177,7 +186,7 @@ public class PlayerAttributes {
return map.containsKey(key);
}
public void removeModifier(String key) {
public AttributeModifier removeModifier(String key) {
AttributeModifier mod = map.remove(key);
/*
@ -190,12 +199,13 @@ public class PlayerAttributes {
((Closeable) mod).close();
update();
}
return mod;
}
public void update() {
PlayerAttribute attribute = MMOCore.plugin.attributeManager.get(id);
PlayerAttribute attr = MMOCore.plugin.attributeManager.get(id);
int total = getTotal();
attribute.getBuffs().forEach(buff -> buff.multiply(total).register(data.getMMOPlayerData()));
attr.getBuffs().forEach(buff -> buff.multiply(total).register(data.getMMOPlayerData()));
}
public String getId() {

View File

@ -13,17 +13,17 @@ 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.stats.StatType;
import net.Indyuce.mmocore.api.util.MMOCoreUtils;
import net.Indyuce.mmocore.api.util.math.formula.LinearValue;
import net.Indyuce.mmocore.experience.EXPSource;
import net.Indyuce.mmocore.loot.chest.particle.CastingParticle;
import net.Indyuce.mmocore.experience.ExpCurve;
import net.Indyuce.mmocore.experience.ExperienceObject;
import net.Indyuce.mmocore.experience.droptable.ExperienceTable;
import net.Indyuce.mmocore.experience.source.type.ExperienceSource;
import net.Indyuce.mmocore.loot.chest.particle.CastingParticle;
import net.Indyuce.mmocore.player.playerclass.ClassTrigger;
import net.Indyuce.mmocore.player.playerclass.ClassTriggerType;
import net.Indyuce.mmocore.player.stats.StatInfo;
import net.Indyuce.mmocore.skill.ClassSkill;
import net.Indyuce.mmocore.skill.RegisteredSkill;
import net.md_5.bungee.api.ChatColor;
@ -51,7 +51,7 @@ public class PlayerClass extends PostLoadObject implements ExperienceObject {
private final ExpCurve expCurve;
private final ExperienceTable expTable;
private final Map<StatType, LinearValue> stats = new HashMap<>();
private final Map<String, LinearValue> stats = new HashMap<>();
private final Map<String, ClassSkill> skills = new LinkedHashMap<>();
private final List<Subclass> subclasses = new ArrayList<>();
@ -124,7 +124,7 @@ public class PlayerClass extends PostLoadObject implements ExperienceObject {
if (config.contains("attributes"))
for (String key : config.getConfigurationSection("attributes").getKeys(false))
try {
stats.put(StatType.valueOf(key.toUpperCase().replace("-", "_")),
stats.put(UtilityMethods.enumName(key),
new LinearValue(config.getConfigurationSection("attributes." + key)));
} catch (IllegalArgumentException exception) {
MMOCore.plugin.getLogger().log(Level.WARNING, "Could not load stat info '" + key + "' from class '"
@ -298,6 +298,18 @@ public class PlayerClass extends PostLoadObject implements ExperienceObject {
return options.containsKey(option) ? options.get(option) : option.getDefault();
}
@Override
public void giveExperience(PlayerData playerData, double experience, @Nullable Location hologramLocation, EXPSource source) {
hologramLocation = !MMOCore.plugin.getConfig().getBoolean("display-main-class-exp-holograms") ? null
: hologramLocation;
playerData.giveExperience(experience, source, hologramLocation, true);
}
@Override
public boolean shouldHandle(PlayerData playerData) {
return equals(playerData.getProfess());
}
@Nullable
@Deprecated
public ClassTrigger getClassTrigger(ClassTriggerType type) {
@ -319,16 +331,11 @@ public class PlayerClass extends PostLoadObject implements ExperienceObject {
return eventTriggers.get(name);
}
@Deprecated
public void setStat(StatType type, double base, double perLevel) {
setStat(type, new LinearValue(base, perLevel));
public void setDefaultStatFormula(String type, LinearValue value) {
stats.put(UtilityMethods.enumName(type), value);
}
public void setStat(StatType type, LinearValue value) {
stats.put(type, value);
}
public double calculateStat(StatType stat, int level) {
public double calculateStat(String stat, int level) {
return getStatInfo(stat).calculate(level);
}
@ -384,8 +391,15 @@ public class PlayerClass extends PostLoadObject implements ExperienceObject {
return skills.values();
}
private LinearValue getStatInfo(StatType type) {
return stats.containsKey(type) ? stats.get(type) : type.getDefault();
@NotNull
private LinearValue getStatInfo(String stat) {
LinearValue found = stats.get(stat);
return found == null ? StatInfo.valueOf(stat).getDefaultFormula() : found;
}
@Override
public boolean equals(Object obj) {
return obj instanceof PlayerClass && ((PlayerClass) obj).id.equals(id);
}
public String getActionBar() {
@ -395,29 +409,4 @@ public class PlayerClass extends PostLoadObject implements ExperienceObject {
public boolean hasActionBar() {
return actionBarFormat != null;
}
@Override
public void giveExperience(PlayerData playerData, double experience, @Nullable Location hologramLocation, EXPSource source) {
hologramLocation = !MMOCore.plugin.getConfig().getBoolean("display-main-class-exp-holograms") ? null
: hologramLocation == null ? getPlayerLocation(playerData) : hologramLocation;
playerData.giveExperience(experience, source, hologramLocation, true);
}
@Override
public boolean shouldHandle(PlayerData playerData) {
return equals(playerData.getProfess());
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
PlayerClass that = (PlayerClass) o;
return id.equals(that.id);
}
@Override
public int hashCode() {
return Objects.hash(id);
}
}

View File

@ -17,13 +17,14 @@ import net.Indyuce.mmocore.skill.RegisteredSkill;
import net.Indyuce.mmocore.manager.data.PlayerDataManager.DefaultPlayerData;
public class SavedClassInformation {
private final int level, experience, skillPoints, attributePoints, attributeReallocationPoints;
private final int level, skillPoints, attributePoints, attributeReallocationPoints;
private final double experience;
private final Map<String, Integer> attributes;
private final Map<String, Integer> skills;
public SavedClassInformation(ConfigurationSection config) {
level = config.getInt("level");
experience = config.getInt("experience");
experience = config.getDouble("experience");
skillPoints = config.getInt("skill-points");
attributePoints = config.getInt("attribute-points");
attributeReallocationPoints = config.getInt("attribute-realloc-points");
@ -38,7 +39,7 @@ public class SavedClassInformation {
public SavedClassInformation(JsonObject json) {
level = json.get("level").getAsInt();
experience = json.get("experience").getAsInt();
experience = json.get("experience").getAsDouble();
skillPoints = json.get("skill-points").getAsInt();
attributePoints = json.get("attribute-points").getAsInt();
attributeReallocationPoints = json.get("attribute-realloc-points").getAsInt();
@ -63,11 +64,11 @@ public class SavedClassInformation {
this(data.getLevel(), 0, data.getSkillPoints(), data.getAttributePoints(), data.getAttrReallocPoints());
}
public SavedClassInformation(int level, int experience, int skillPoints, int attributePoints, int attributeReallocationPoints) {
public SavedClassInformation(int level, double experience, int skillPoints, int attributePoints, int attributeReallocationPoints) {
this(level, experience, skillPoints, attributePoints, attributeReallocationPoints, new HashMap<>(), new HashMap<>());
}
private SavedClassInformation(int level, int experience, int skillPoints, int attributePoints, int attributeReallocationPoints,
private SavedClassInformation(int level, double experience, int skillPoints, int attributePoints, int attributeReallocationPoints,
Map<String, Integer> attributes, Map<String, Integer> skills) {
this.level = level;
this.experience = experience;
@ -82,7 +83,7 @@ public class SavedClassInformation {
return level;
}
public int getExperience() {
public double getExperience() {
return experience;
}

View File

@ -3,7 +3,6 @@ package net.Indyuce.mmocore.api.player.profess.resource;
import net.Indyuce.mmocore.api.event.PlayerResourceUpdateEvent;
import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.api.player.profess.ClassOption;
import net.Indyuce.mmocore.api.player.stats.StatType;
import net.Indyuce.mmocore.api.quest.trigger.ManaTrigger;
import org.bukkit.attribute.Attribute;
@ -20,27 +19,27 @@ public enum PlayerResource {
(data, amount) -> data.getPlayer().setHealth(amount)),
MANA(PlayerData::getMana,
data -> data.getStats().getStat(StatType.MAX_MANA),
data -> data.getStats().getStat("MAX_MANA"),
(data, amount) -> data.giveMana(amount, PlayerResourceUpdateEvent.UpdateReason.REGENERATION),
(data, amount) -> data.giveMana(amount, PlayerResourceUpdateEvent.UpdateReason.COMMAND),
(data, amount) -> data.giveMana(-amount, PlayerResourceUpdateEvent.UpdateReason.COMMAND),
(data, amount) -> data.setMana(amount)),
STAMINA(PlayerData::getStamina,
data -> data.getStats().getStat(StatType.MAX_STAMINA),
data -> data.getStats().getStat("MAX_STAMINA"),
(data, amount) -> data.giveStamina(amount, PlayerResourceUpdateEvent.UpdateReason.REGENERATION),
(data, amount) -> data.giveStamina(amount, PlayerResourceUpdateEvent.UpdateReason.COMMAND),
(data, amount) -> data.giveStamina(-amount, PlayerResourceUpdateEvent.UpdateReason.COMMAND),
(data, amount) -> data.setStamina(amount)),
STELLIUM(PlayerData::getStellium,
data -> data.getStats().getStat(StatType.MAX_STELLIUM),
data -> data.getStats().getStat("MAX_STELLIUM"),
(data, amount) -> data.giveStellium(amount, PlayerResourceUpdateEvent.UpdateReason.REGENERATION),
(data, amount) -> data.giveStellium(amount, PlayerResourceUpdateEvent.UpdateReason.COMMAND),
(data, amount) -> data.giveStellium(-amount, PlayerResourceUpdateEvent.UpdateReason.COMMAND),
(data, amount) -> data.setStellium(amount));
private final StatType regenStat, maxRegenStat;
private final String regenStat, maxRegenStat;
private final ClassOption offCombatRegen;
private final Function<PlayerData, Double> current, max;
private final BiConsumer<PlayerData, Double> regen;
@ -54,8 +53,8 @@ public enum PlayerResource {
BiConsumer<PlayerData, Double> give,
BiConsumer<PlayerData, Double> take,
BiConsumer<PlayerData, Double> set) {
this.regenStat = StatType.valueOf(name() + "_REGENERATION");
this.maxRegenStat = StatType.valueOf("MAX_" + name() + "_REGENERATION");
this.regenStat = name() + "_REGENERATION";
this.maxRegenStat = "MAX_" + name() + "_REGENERATION";
this.offCombatRegen = ClassOption.valueOf("OFF_COMBAT_" + name() + "_REGEN");
this.current = current;
this.max = max;
@ -68,14 +67,14 @@ public enum PlayerResource {
/**
* @return Stat which corresponds to flat resource regeneration
*/
public StatType getRegenStat() {
public String getRegenStat() {
return regenStat;
}
/**
* @return Stat which corresponds to resource regeneration scaling with the player's max health
*/
public StatType getMaxRegenStat() {
public String getMaxRegenStat() {
return maxRegenStat;
}

View File

@ -8,17 +8,14 @@ import io.lumine.mythic.lib.player.modifier.ModifierSource;
import io.lumine.mythic.lib.player.modifier.ModifierType;
import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.experience.Profession;
import net.Indyuce.mmocore.player.stats.StatInfo;
import net.Indyuce.mmocore.skill.ClassSkill;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Locale;
public class PlayerStats {
private final PlayerData data;
/**
* Utilclass to easily manipulate the MMOLib stat map
* Util class to easily manipulate the MMOLib stat map
*
* @param data Playerdata
*/
@ -34,6 +31,7 @@ public class PlayerStats {
return data.getMMOPlayerData().getStatMap();
}
@Deprecated
public StatInstance getInstance(StatType stat) {
return getMap().getInstance(stat.name());
}
@ -42,35 +40,26 @@ public class PlayerStats {
return getMap().getInstance(stat);
}
/**
* Allows for stat type enum to have dynamic professions.
* ID FORMAT: STAT_TYPE_HERE_PROFESSION_HERE
*
* @param type the type of stat
* @param profession the stat's specific permission
* @return instance of found stat
* @author Ehhthan
*/
@NotNull
public StatInstance getInstance(StatType type, @Nullable Profession profession) {
if (profession == null)
return getInstance(type);
else {
String id = (type.name() + '_' + profession.getId()).replace('-', '_').replace(' ', '_').toUpperCase(Locale.ROOT);
return getInstance(id);
}
}
/*
* applies relative attributes on the base stat too
*/
public double getStat(StatType stat) {
public double getStat(String stat) {
return getInstance(stat).getTotal();
}
public double getBase(StatType stat) {
return data.getProfess().calculateStat(stat,
stat.hasProfession() ? data.getCollectionSkills().getLevel(stat.getProfession()) : data.getLevel());
/**
* MMOCore base stat value differs from the on in MythicLib.
* <p>
* MythicLib: the base stat value is only defined for stats
* which are based on vanilla player attributes. It corresponds
* to the stat amount any player has with NO attribute modifier whatsoever.
* <p>
* MMOCore: the base stat value corresponds to the stat amount
* the player CLASS grants. It can be similar or equal to the one
* in MMOCore but it really is completely different.
*
* @return MMOCore base stat value
*/
public double getBase(String stat) {
Profession profession = StatInfo.valueOf(stat).profession;
return data.getProfess().calculateStat(stat, profession == null ? data.getLevel() : data.getCollectionSkills().getLevel(profession));
}
/**
@ -81,7 +70,7 @@ public class PlayerStats {
* see {@link PlayerData#update()} for more info
*/
public synchronized void updateStats() {
for (StatType stat : StatType.values()) {
for (StatType stat : StatType.values()) { // TODO fix
StatInstance instance = getMap().getInstance(stat.name());
StatInstance.ModifierPacket packet = instance.newPacket();
@ -89,7 +78,7 @@ public class PlayerStats {
packet.removeIf(str -> str.equals("mmocoreClass"));
// Add newest one
double total = getBase(stat) - instance.getBase();
double total = getBase(stat.name()) - instance.getBase();
if (total != 0)
packet.addModifier(new StatModifier("mmocoreClass", stat.name(), total, ModifierType.FLAT, EquipmentSlot.OTHER, ModifierSource.OTHER));

View File

@ -1,14 +1,14 @@
package net.Indyuce.mmocore.api.player.stats;
import io.lumine.mythic.lib.MythicLib;
import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.ConfigFile;
import net.Indyuce.mmocore.api.util.math.formula.LinearValue;
import net.Indyuce.mmocore.experience.Profession;
import org.bukkit.configuration.file.FileConfiguration;
import net.Indyuce.mmocore.player.stats.StatInfo;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.text.DecimalFormat;
import java.util.Objects;
@Deprecated
public enum StatType {
// Vanilla stats
@ -61,6 +61,7 @@ public enum StatType {
// Utility
ADDITIONAL_EXPERIENCE,
COOLDOWN_REDUCTION,
CHANCE,
// Damage-type based stats
MAGIC_DAMAGE,
@ -86,17 +87,17 @@ public enum StatType {
/**
* Reduces amount of tugs needed to fish
*/
FISHING_STRENGTH("fishing"),
FISHING_STRENGTH,
/**
* Chance of instant success when fishing
*/
CRITICAL_FISHING_CHANCE("fishing"),
CRITICAL_FISHING_CHANCE,
/**
* Chance of crit fishing failure
*/
CRITICAL_FISHING_FAILURE_CHANCE("fishing"),
CRITICAL_FISHING_FAILURE_CHANCE,
/**
* Chance of dropping more minerals when mining.
@ -113,49 +114,35 @@ public enum StatType {
*/
LUCK_OF_THE_FIELD;
private String profession;
private LinearValue defaultInfo;
private DecimalFormat format;
StatType() {
// Completely custom stat
}
@SuppressWarnings("SameParameterValue")
StatType(String profession) {
this.profession = profession;
}
@Deprecated
public String getProfession() {
return profession;
return findProfession().getId();
}
@Deprecated
@Nullable
public Profession findProfession() {
return MMOCore.plugin.professionManager.get(profession);
return StatInfo.valueOf(name()).profession;
}
@Deprecated
public boolean hasProfession() {
return profession != null;
return findProfession() != null;
}
@Deprecated
@NotNull
public LinearValue getDefault() {
return defaultInfo;
return StatInfo.valueOf(name()).getDefaultFormula();
}
@Deprecated
public boolean matches(Profession profession) {
return this.profession != null && this.profession.equals(profession.getId());
return Objects.equals(findProfession(), profession);
}
@Deprecated
public String format(double value) {
return format.format(value);
}
public static void load() {
FileConfiguration config = new ConfigFile("stats").getConfig();
for (StatType stat : values()) {
stat.defaultInfo = config.contains("default." + stat.name()) ? new LinearValue(config.getConfigurationSection("default." + stat.name())) : new LinearValue(0, 0);
stat.format = MythicLib.plugin.getMMOConfig().newDecimalFormat(config.contains("decimal-format." + stat.name()) ? config.getString("decimal-format." + stat.name()) : "0.#");
}
return StatInfo.valueOf(name()).format(value);
}
}

View File

@ -1,6 +1,7 @@
package net.Indyuce.mmocore.api.quest.trigger;
import net.Indyuce.mmocore.experience.ExperienceObject;
import net.Indyuce.mmocore.experience.SimpleExperienceObject;
import net.Indyuce.mmocore.experience.dispenser.ExperienceDispenser;
import org.apache.commons.lang.Validate;
import net.Indyuce.mmocore.MMOCore;
@ -9,17 +10,14 @@ import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.api.util.math.formula.RandomAmount;
import io.lumine.mythic.lib.api.MMOLineConfig;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Objects;
public class ExperienceTrigger extends Trigger {
@NotNull
private final RandomAmount amount;
@NotNull
private final EXPSource source;
@Nullable
private final ExperienceObject expObject;
@NotNull
private final ExperienceDispenser dispenser;
public ExperienceTrigger(MMOLineConfig config) {
super(config);
@ -29,15 +27,15 @@ public class ExperienceTrigger extends Trigger {
if (config.contains("profession")) {
String id = config.getString("profession").toLowerCase().replace("_", "-");
Validate.isTrue(MMOCore.plugin.professionManager.has(id), "Could not find profession");
expObject = MMOCore.plugin.professionManager.get(id);
dispenser = MMOCore.plugin.professionManager.get(id);
} else
expObject = null;
dispenser = new SimpleExperienceObject();
amount = new RandomAmount(config.getString("amount"));
source = config.contains("source") ? EXPSource.valueOf(config.getString("source").toUpperCase()) : EXPSource.QUEST;
}
@Override
public void apply(PlayerData player) {
Objects.requireNonNullElse(expObject, player.getProfess()).giveExperience(player, amount.calculateInt(), null, source);
dispenser.giveExperience(player, amount.calculateInt(), null, source);
}
}

View File

@ -196,7 +196,7 @@ public class MMOCoreUtils {
*/
public static void decreaseDurability(Player player, EquipmentSlot slot, int damage) {
ItemStack item = player.getInventory().getItem(slot);
if (!item.hasItemMeta() || !(item.getItemMeta() instanceof Damageable) || item.getItemMeta().isUnbreakable())
if (item == null || item.getType().getMaxDurability() == 0 || !item.hasItemMeta() || !(item.getItemMeta() instanceof Damageable) || item.getItemMeta().isUnbreakable())
return;
PlayerItemDamageEvent event = new PlayerItemDamageEvent(player, item, damage);

View File

@ -110,4 +110,16 @@ public class LinearValue {
return value;
}
@Override
public String toString() {
return "LinearValue{" +
"base=" + base +
", perLevel=" + perLevel +
", min=" + min +
", max=" + max +
", hasmin=" + hasmin +
", hasmax=" + hasmax +
'}';
}
}

View File

@ -58,8 +58,8 @@ public class ExperienceCommandTreeNode extends CommandTreeNode {
int amount;
try {
amount = Integer.parseInt(args[5]);
Validate.isTrue(amount > 0);
} catch (NumberFormatException exception) {
Validate.isTrue(amount >= 0);
} catch (RuntimeException exception) {
sender.sendMessage(ChatColor.RED + args[5] + " is not a valid number.");
return CommandResult.FAILURE;
}

View File

@ -1,11 +1,11 @@
package net.Indyuce.mmocore.command.rpg.debug;
import io.lumine.mythic.lib.UtilityMethods;
import io.lumine.mythic.lib.api.stat.StatInstance;
import io.lumine.mythic.lib.api.stat.modifier.StatModifier;
import io.lumine.mythic.lib.command.api.CommandTreeNode;
import io.lumine.mythic.lib.command.api.Parameter;
import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.api.player.stats.StatType;
import org.bukkit.ChatColor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
@ -15,10 +15,7 @@ public class StatModifiersCommandTreeNode extends CommandTreeNode {
public StatModifiersCommandTreeNode(CommandTreeNode parent) {
super(parent, "statmods");
addParameter(new Parameter("<stat>", (explorer, list) -> {
for (StatType stat : StatType.values())
list.add(stat.name());
}));
addParameter(new Parameter("<stat>", (explorer, list) -> list.add("STAT_ID")));
}
@Override
@ -32,15 +29,7 @@ public class StatModifiersCommandTreeNode extends CommandTreeNode {
}
PlayerData data = PlayerData.get((Player) sender);
StatType stat;
try {
stat = StatType.valueOf(args[2].toUpperCase().replace("-", "_").replace(" ", "_"));
} catch (IllegalArgumentException exception) {
sender.sendMessage(ChatColor.RED + "Could not find stat: " + args[2] + ".");
return CommandResult.FAILURE;
}
StatInstance instance = data.getStats().getInstance(stat);
StatInstance instance = data.getStats().getInstance(UtilityMethods.enumName(args[2]));
sender.sendMessage("Stat Modifiers (" + instance.getKeys().size() + "):");
for (String key : instance.getKeys()) {
StatModifier mod = instance.getModifier(key);

View File

@ -1,51 +1,36 @@
package net.Indyuce.mmocore.command.rpg.debug;
import io.lumine.mythic.lib.UtilityMethods;
import io.lumine.mythic.lib.command.api.CommandTreeNode;
import io.lumine.mythic.lib.command.api.Parameter;
import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.player.stats.StatInfo;
import org.bukkit.ChatColor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.api.player.stats.StatType;
import io.lumine.mythic.lib.command.api.CommandTreeNode;
import io.lumine.mythic.lib.command.api.Parameter;
public class StatValueCommandTreeNode extends CommandTreeNode {
public StatValueCommandTreeNode(CommandTreeNode parent) {
super(parent, "statvalue");
public StatValueCommandTreeNode(CommandTreeNode parent) {
super(parent, "statvalue");
addParameter(new Parameter("<stat>", (explorer, list) -> {
for (StatType stat : StatType.values())
list.add(stat.name());
}));
addParameter(new Parameter("(formatted)", (explorer, list) -> list.add("true")));
}
addParameter(new Parameter("<stat>", (explorer, list) -> list.add("STAT_ID")));
}
@Override
public CommandResult execute(CommandSender sender, String[] args) {
if (args.length < 3)
return CommandResult.THROW_USAGE;
@Override
public CommandResult execute(CommandSender sender, String[] args) {
if (args.length < 3)
return CommandResult.THROW_USAGE;
if (!(sender instanceof Player)) {
sender.sendMessage(ChatColor.RED + "This command can only be used by a player.");
return CommandResult.FAILURE;
}
PlayerData data = PlayerData.get((Player) sender);
if (!(sender instanceof Player)) {
sender.sendMessage(ChatColor.RED + "This command can only be used by a player.");
return CommandResult.FAILURE;
}
PlayerData data = PlayerData.get((Player) sender);
StatType stat;
try {
stat = StatType.valueOf(args[2].toUpperCase().replace("-", "_").replace(" ", "_"));
} catch (IllegalArgumentException exception) {
sender.sendMessage(ChatColor.RED + "Could not find stat: " + args[2] + ".");
return CommandResult.FAILURE;
}
StatInfo stat = StatInfo.valueOf(UtilityMethods.enumName(args[2]));
sender.sendMessage(DebugCommandTreeNode.commandPrefix + "Stat Value (" + ChatColor.BLUE + stat.name + ChatColor.WHITE + "): "
+ ChatColor.GREEN + data.getStats().getStat(stat.name));
if (args.length > 3 && args[3].equals("true"))
sender.sendMessage(DebugCommandTreeNode.commandPrefix + "Stat Value (" + ChatColor.BLUE + stat.name() + ChatColor.WHITE + "): "
+ ChatColor.GREEN + stat.format(data.getStats().getStat(stat)) + ChatColor.WHITE + " *");
else
sender.sendMessage(DebugCommandTreeNode.commandPrefix + "Stat Value (" + ChatColor.BLUE + stat.name() + ChatColor.WHITE + "): "
+ ChatColor.GREEN + data.getStats().getStat(stat));
return CommandResult.SUCCESS;
}
return CommandResult.SUCCESS;
}
}

View File

@ -0,0 +1,44 @@
package net.Indyuce.mmocore.command.rpg.waypoint;
import io.lumine.mythic.lib.api.util.SmartGive;
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.util.item.WaypointBookBuilder;
import net.Indyuce.mmocore.waypoint.Waypoint;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
public class ItemCommandTreeNode extends CommandTreeNode {
public ItemCommandTreeNode(CommandTreeNode parent) {
super(parent, "item");
addParameter(new Parameter("<waypoint>", (explorer, list) -> MMOCore.plugin.waypointManager.getAll().forEach(way -> list.add(way.getId()))));
addParameter(Parameter.PLAYER);
}
@Override
public CommandResult execute(CommandSender sender, String[] args) {
if (args.length < 4)
return CommandResult.THROW_USAGE;
if (!MMOCore.plugin.waypointManager.has(args[2])) {
sender.sendMessage(ChatColor.RED + "Could not find waypoint " + args[2]);
return CommandResult.FAILURE;
}
Player player = Bukkit.getPlayer(args[3]);
if (player == null) {
sender.sendMessage(ChatColor.RED + "Could not find player " + args[3]);
return CommandResult.FAILURE;
}
Waypoint waypoint = MMOCore.plugin.waypointManager.get(args[2]);
new SmartGive(player).give(new WaypointBookBuilder(waypoint).build());
sender.sendMessage(ChatColor.GOLD + "Gave " + player.getName() + ChatColor.YELLOW + " a waypoint book of " + ChatColor.GOLD + waypoint.getId()
+ ChatColor.YELLOW + ".");
return CommandResult.SUCCESS;
}
}

View File

@ -11,6 +11,7 @@ public class WaypointsCommandTreeNode extends CommandTreeNode {
addChild(new UnlockCommandTreeNode(this));
addChild(new OpenCommandTreeNode(this));
addChild(new TeleportCommandTreeNode(this));
addChild(new ItemCommandTreeNode(this));
}
@Override

View File

@ -1,28 +0,0 @@
package net.Indyuce.mmocore.comp;
import io.lumine.mythic.lib.comp.target.InteractionType;
import io.lumine.mythic.lib.comp.target.TargetRestriction;
import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.party.AbstractParty;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import java.util.Optional;
public class MMOCoreTargetRestriction implements TargetRestriction {
@Override
public boolean canTarget(Player player, LivingEntity target, InteractionType interaction) {
if (interaction.isOffense() && target instanceof Player && PlayerData.has(target.getUniqueId())) {
PlayerData targetData = PlayerData.get(target.getUniqueId());
// Check for the same party
AbstractParty party = targetData.getParty();
if (party != null && party.hasMember(player))
return false;
}
return true;
}
}

View File

@ -5,7 +5,7 @@ import io.lumine.mythic.lib.api.util.AltChar;
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.api.player.stats.StatType;
import net.Indyuce.mmocore.player.stats.StatInfo;
import net.Indyuce.mmocore.api.quest.PlayerQuests;
import net.Indyuce.mmocore.experience.PlayerProfessions;
import net.Indyuce.mmocore.experience.Profession;
@ -72,11 +72,11 @@ public class RPGPlaceholders extends PlaceholderExpansion {
}
else if (identifier.equals("health") && player.isOnline()) {
return StatType.MAX_HEALTH.format(player.getPlayer().getHealth());
return StatInfo.valueOf("MAX_HEALTH").format(player.getPlayer().getHealth());
}
else if (identifier.equals("max_health") && player.isOnline()) {
return StatType.MAX_HEALTH.format(player.getPlayer().getAttribute(Attribute.GENERIC_MAX_HEALTH).getValue());
return StatInfo.valueOf("MAX_HEALTH").format(player.getPlayer().getAttribute(Attribute.GENERIC_MAX_HEALTH).getValue());
}
else if (identifier.equals("health_bar") && player.isOnline()) {
@ -153,7 +153,7 @@ public class RPGPlaceholders extends PlaceholderExpansion {
return MythicLib.plugin.getMMOConfig().decimal.format(playerData.getMana());
else if (identifier.equals("mana_bar")) {
return playerData.getProfess().getManaDisplay().generateBar(playerData.getMana(), playerData.getStats().getStat(StatType.MAX_MANA));
return playerData.getProfess().getManaDisplay().generateBar(playerData.getMana(), playerData.getStats().getStat("MAX_MANA"));
}
else if (identifier.startsWith("exp_multiplier_")) {
@ -173,7 +173,7 @@ public class RPGPlaceholders extends PlaceholderExpansion {
else if (identifier.equals("stamina_bar")) {
StringBuilder format = new StringBuilder();
double ratio = 20 * playerData.getStamina() / playerData.getStats().getStat(StatType.MAX_STAMINA);
double ratio = 20 * playerData.getStamina() / playerData.getStats().getStat("MAX_STAMINA");
for (double j = 1; j < 20; j++)
format.append(ratio >= j ? MMOCore.plugin.configManager.staminaFull
: ratio >= j - .5 ? MMOCore.plugin.configManager.staminaHalf : MMOCore.plugin.configManager.staminaEmpty)
@ -182,8 +182,8 @@ public class RPGPlaceholders extends PlaceholderExpansion {
}
else if (identifier.startsWith("stat_")) {
StatType type = StatType.valueOf(identifier.substring(5).toUpperCase());
return type == null ? "Invalid Stat" : type.format(playerData.getStats().getStat(type));
StatInfo info = StatInfo.valueOf(identifier.substring(5).toUpperCase());
return info.format(playerData.getStats().getStat(info.name));
}
else if (identifier.equals("stellium"))
@ -191,7 +191,7 @@ public class RPGPlaceholders extends PlaceholderExpansion {
else if (identifier.equals("stellium_bar")) {
StringBuilder format = new StringBuilder();
double ratio = 20 * playerData.getStellium() / playerData.getStats().getStat(StatType.MAX_STELLIUM);
double ratio = 20 * playerData.getStellium() / playerData.getStats().getStat("MAX_STELLIUM");
for (double j = 1; j < 20; j++)
format.append(ratio >= j ? ChatColor.BLUE : ratio >= j - .5 ? ChatColor.AQUA : ChatColor.WHITE).append(AltChar.listSquare);
return format.toString();

View File

@ -3,8 +3,8 @@ package net.Indyuce.mmocore.comp.region;
import java.util.Arrays;
import java.util.List;
import net.Indyuce.mmocore.loot.droptable.condition.Condition;
import net.Indyuce.mmocore.loot.droptable.condition.ConditionInstance;
import net.Indyuce.mmocore.loot.chest.condition.Condition;
import net.Indyuce.mmocore.loot.chest.condition.ConditionInstance;
import io.lumine.mythic.lib.api.MMOLineConfig;
public class RegionCondition extends Condition {

View File

@ -1,6 +1,6 @@
package net.Indyuce.mmocore.comp.region;
import net.Indyuce.mmocore.loot.droptable.condition.Condition;
import net.Indyuce.mmocore.loot.chest.condition.Condition;
import net.Indyuce.mmocore.api.load.MMOLoader;
import io.lumine.mythic.lib.api.MMOLineConfig;

View File

@ -1,16 +1,16 @@
package net.Indyuce.mmocore.experience;
import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.api.util.MMOCoreUtils;
import net.Indyuce.mmocore.experience.dispenser.ExperienceDispenser;
import net.Indyuce.mmocore.experience.droptable.ExperienceTable;
import org.bukkit.Location;
import org.jetbrains.annotations.NotNull;
import javax.annotation.Nullable;
/**
* Either a profession or a class
* General implementation for professions, classes and attributes.
* <p>
* An experience object is a type of object that can level up.
* It has an experience curve and table and can receive EXP
*
* @author jules
*/
@ -26,40 +26,11 @@ public interface ExperienceObject extends ExperienceDispenser {
@Nullable
ExpCurve getExpCurve();
boolean hasExperienceTable();
/**
* @return Table read when leveling up
*/
@NotNull
ExperienceTable getExperienceTable();
/**
* Called when experience is gained in main class/profession
*
* @param playerData Player gaining the experience
* @param experience Experience gained. Note that it is a double
* because it gets converted to an integer at
* the very last moment in MMOCore
* @param hologramLocation Location of displayed hologram. When set to null
* and if exp holograms are enabled it will take the
* player's location instead.
* @param source Why the EXP was gained
*/
void giveExperience(PlayerData playerData, double experience, @org.jetbrains.annotations.Nullable Location hologramLocation, @NotNull EXPSource source);
/**
* Experience sources handle both CLASS experience sources and PROFESSION
* experience sources. Professions have no problem because whatever
* class the player has chosen, he can get exp in that profession.
* <p>
* But class experience sources must first make sure that the player has
* the right class before giving exp to the player
*/
boolean shouldHandle(PlayerData playerData);
@Nullable
default Location getPlayerLocation(PlayerData player) {
return player.isOnline() ? MMOCoreUtils.getCenterLocation(player.getPlayer()) : null;
}
boolean hasExperienceTable();
}

View File

@ -4,13 +4,13 @@ import com.google.gson.Gson;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import io.lumine.mythic.lib.MythicLib;
import io.lumine.mythic.lib.UtilityMethods;
import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.ConfigMessage;
import net.Indyuce.mmocore.api.SoundEvent;
import net.Indyuce.mmocore.api.event.PlayerExperienceGainEvent;
import net.Indyuce.mmocore.api.event.PlayerLevelUpEvent;
import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.api.player.stats.StatType;
import net.Indyuce.mmocore.api.util.MMOCoreUtils;
import net.Indyuce.mmocore.loot.chest.particle.SmallParticleEffect;
import org.apache.commons.lang.Validate;
@ -26,7 +26,7 @@ import java.util.Map;
import java.util.Map.Entry;
public class PlayerProfessions {
private final Map<String, Integer> exp = new HashMap<>();
private final Map<String, Double> exp = new HashMap<>();
private final Map<String, Integer> level = new HashMap<>();
private final PlayerData playerData;
@ -41,7 +41,7 @@ public class PlayerProfessions {
public PlayerProfessions load(ConfigurationSection config) {
for (String key : config.getKeys(false))
if (MMOCore.plugin.professionManager.has(key)) {
exp.put(key, config.getInt(key + ".exp"));
exp.put(key, config.getDouble(key + ".exp"));
level.put(key, config.getInt(key + ".level"));
}
@ -89,7 +89,7 @@ public class PlayerProfessions {
for (Entry<String, JsonElement> entry : obj.entrySet())
if (MMOCore.plugin.professionManager.has(entry.getKey())) {
JsonObject value = entry.getValue().getAsJsonObject();
exp.put(entry.getKey(), value.get("exp").getAsInt());
exp.put(entry.getKey(), value.get("exp").getAsDouble());
level.put(entry.getKey(), value.get("level").getAsInt());
}
@ -111,11 +111,11 @@ public class PlayerProfessions {
return getLevel(profession.getId());
}
public int getExperience(String id) {
return exp.getOrDefault(id, 0);
public double getExperience(String id) {
return exp.getOrDefault(id, 0.);
}
public int getExperience(Profession profession) {
public double getExperience(Profession profession) {
return getExperience(profession.getId());
}
@ -136,7 +136,7 @@ public class PlayerProfessions {
level.put(profession.getId(), Math.max(1, current - value));
}
public void setExperience(Profession profession, int value) {
public void setExperience(Profession profession, double value) {
exp.put(profession.getId(), value);
}
@ -147,7 +147,7 @@ public class PlayerProfessions {
giveExperience(profession, total, source);
}
public void giveExperience(Profession profession, int value, EXPSource source) {
public void giveExperience(Profession profession, double value, EXPSource source) {
giveExperience(profession, value, source, null);
}
@ -157,6 +157,8 @@ public class PlayerProfessions {
public void giveExperience(Profession profession, double value, EXPSource source, @Nullable Location hologramLocation) {
Validate.isTrue(playerData.isOnline(), "Cannot give experience to offline player");
if (value <= 0)
return;
if (hasReachedMaxLevel(profession)) {
setExperience(profession, 0);
@ -166,19 +168,20 @@ public class PlayerProfessions {
value = MMOCore.plugin.boosterManager.calculateExp(profession, value);
// Adds functionality for additional experience per profession.
value *= 1 + playerData.getStats().getInstance(StatType.ADDITIONAL_EXPERIENCE, profession).getTotal() / 100;
value *= 1 + playerData.getStats().getInstance("ADDITIONAL_EXPERIENCE_" + UtilityMethods.enumName(profession.getId())).getTotal() / 100;
// Display hologram
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);
PlayerExperienceGainEvent event = new PlayerExperienceGainEvent(playerData, profession, value, source);
Bukkit.getPluginManager().callEvent(event);
if (event.isCancelled())
return;
exp.put(profession.getId(), Math.max(0, exp.getOrDefault(profession.getId(), 0) + event.getExperience()));
int needed, exp, level, oldLevel = getLevel(profession);
exp.put(profession.getId(), Math.max(0, exp.getOrDefault(profession.getId(), 0.) + event.getExperience()));
int level, oldLevel = getLevel(profession);
double needed,exp;
/*
* Loop for exp overload when leveling up, will continue
@ -195,7 +198,7 @@ public class PlayerProfessions {
this.exp.put(profession.getId(), exp - needed);
this.level.put(profession.getId(), level + 1);
check = true;
playerData.giveExperience((int) profession.getExperience().calculate(level), null);
playerData.giveExperience(profession.getExperience().calculate(level), null);
}
if (check) {

View File

@ -64,7 +64,7 @@ public class Profession extends PostLoadObject implements ExperienceObject {
maxLevel = config.getInt("max-level");
if (config.contains("exp-sources")) {
if (config.contains("exp-sources"))
for (String key : config.getStringList("exp-sources"))
try {
MMOCore.plugin.experience.registerSource(MMOCore.plugin.loadManager.loadExperienceSource(new MMOLineConfig(key), this));
@ -72,7 +72,6 @@ public class Profession extends PostLoadObject implements ExperienceObject {
MMOCore.plugin.getLogger().log(Level.WARNING,
"Could not register exp source '" + key + "' from profession '" + id + "': " + exception.getMessage());
}
}
}
@Override
@ -127,7 +126,7 @@ public class Profession extends PostLoadObject implements ExperienceObject {
@Override
public void giveExperience(PlayerData playerData, double experience, @Nullable Location hologramLocation, EXPSource source) {
hologramLocation = !getOption(Profession.ProfessionOption.EXP_HOLOGRAMS) ? null
: hologramLocation == null ? getPlayerLocation(playerData) : hologramLocation;
: hologramLocation;
playerData.getCollectionSkills().giveExperience(this, experience, EXPSource.SOURCE, hologramLocation);
}

View File

@ -0,0 +1,22 @@
package net.Indyuce.mmocore.experience;
import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.experience.dispenser.ExperienceDispenser;
import org.bukkit.Location;
import org.jetbrains.annotations.Nullable;
public class SimpleExperienceObject implements ExperienceDispenser {
@Override
public void giveExperience(PlayerData playerData, double experience, @Nullable Location hologramLocation, EXPSource source) {
hologramLocation = !MMOCore.plugin.getConfig().getBoolean("display-main-class-exp-holograms") ? null
: hologramLocation == null ? getPlayerLocation(playerData) : hologramLocation;
playerData.giveExperience(experience, source, hologramLocation, true);
}
@Override
public boolean shouldHandle(PlayerData playerData) {
return true;
}
}

View File

@ -21,9 +21,7 @@ public interface ExperienceDispenser {
* Called when experience is gained in main class/profession
*
* @param playerData Player gaining the experience
* @param experience Experience gained. Note that it is a double
* because it gets converted to an integer at
* the very last moment in MMOCore
* @param experience Experience gained
* @param hologramLocation Location of displayed hologram. When set to null
* and if exp holograms are enabled it will take the
* player's location instead.

View File

@ -13,7 +13,10 @@ import java.util.Random;
public class ExperienceItem {
private final String id;
//A period of 0 means the item will only trigger one time.
private final int period;
private final int firstTrigger;
private final double claimChance, failReduction;
private final List<Trigger> triggers;
@ -23,6 +26,7 @@ public class ExperienceItem {
* One item for an experience table
*
* @param period The experience item is claimed every X level ups
* @param firstTrigger The experience item if claimed for the first time at 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.
@ -32,19 +36,22 @@ public class ExperienceItem {
* 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<Trigger> triggers) {
public ExperienceItem(String id, int period, int firstTrigger, double claimChance, double failReduction, List<Trigger> triggers) {
this.id = id;
this.period = period;
this.claimChance = claimChance;
this.failReduction = failReduction;
this.triggers = triggers;
this.firstTrigger = firstTrigger;
}
public ExperienceItem(ConfigurationSection config) {
Validate.notNull(config, "Config cannot be null");
Validate.isTrue(config.contains("triggers"));
id = config.getName();
period = config.getInt("period", 1);
period = config.getInt("period", 0);
firstTrigger = config.getInt("first-trigger", period);
claimChance = config.getDouble("chance", 100) / 100;
failReduction = config.getDouble("fail-reduction", 80) / 100;
triggers = new ArrayList<>();
@ -64,7 +71,7 @@ public class ExperienceItem {
* account the randomness factor from the 'chance' parameter
*/
public boolean roll(int professionLevel, int timesCollected) {
int claimsRequired = professionLevel - (timesCollected + 1) * period;
int claimsRequired = professionLevel + 1 - (firstTrigger - timesCollected * period);
if (claimsRequired < 1)
return false;

View File

@ -168,7 +168,7 @@ public class BrewPotionExperienceSource extends ExperienceSource<PotionMeta> {
*/
// exp += getTotal(mapEffectDurations());
getDispenser().giveExperience(PlayerData.get(player), (int) exp * multiplier, null, EXPSource.SOURCE);
getDispenser().giveExperience(PlayerData.get(player), exp * multiplier, player.getLocation(), EXPSource.SOURCE);
}
}
}

View File

@ -0,0 +1,75 @@
package net.Indyuce.mmocore.experience.source;
import io.lumine.mythic.lib.api.MMOLineConfig;
import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.experience.dispenser.ExperienceDispenser;
import net.Indyuce.mmocore.experience.source.type.SpecificExperienceSource;
import net.Indyuce.mmocore.manager.profession.ExperienceSourceManager;
import org.apache.commons.lang.Validate;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.event.EventHandler;
import org.bukkit.event.player.PlayerMoveEvent;
import org.bukkit.util.Vector;
public class ClimbExperienceSource extends SpecificExperienceSource<Material> {
//Can be Ladder,Vines,Twisting Vines,Weeping Vines.
private final Material type;
/**
* Gives Experience when a player climbs on a ladder, a vine, a twisting vine or a weeping vine depending
* on the type precised (if no type is precised it will give xp for the 4)
* The xp given depends on the vertical distance travelled, the random amount given correspond
* to the xp when you climb, one block
*/
public ClimbExperienceSource(ExperienceDispenser dispenser, MMOLineConfig config) {
super(dispenser, config);
//If no type precised Ladder and all vines types work
if (!config.contains("type"))
type = null;
else {
String str = config.getString("type").toUpperCase().replace("-", "_");
Validate.isTrue(str.equals("LADDER") ||
str.equals("VINE") || str.equals("TWISTING_VINES_PLANT") || str.equals("WEEPING_VINES"),
"ClimbExperienceSource problem: The type must be ladder, vine, twisted-vines or weeping-vines");
type = Material.valueOf(str);
}
}
@Override
public ExperienceSourceManager<ClimbExperienceSource> newManager() {
return new ExperienceSourceManager<ClimbExperienceSource>() {
@EventHandler
public void onClimb(PlayerMoveEvent e) {
double delta=e.getTo().getBlockY()-e.getFrom().getBlockY();
if (delta > 0) {
if (e.getPlayer().hasMetadata("NPC"))
return;
PlayerData playerData = PlayerData.get(e.getPlayer());
for (ClimbExperienceSource source : getSources()) {
if (source.matchesParameter(playerData, e.getFrom().getBlock().getType()))
source.giveExperience(playerData, delta, null);
}
}
}
};
}
@Override
public boolean matchesParameter(PlayerData player, Material material) {
if (type == null)
return material.equals(Material.LADDER) || material.equals(Material.VINE) ||
material.equals(Material.WEEPING_VINES) || material.equals(Material.TWISTING_VINES) ||
material.equals(Material.WEEPING_VINES_PLANT) || material.equals(Material.TWISTING_VINES_PLANT);
if (type.equals(Material.WEEPING_VINES))
return material.equals(Material.WEEPING_VINES) || material.equals(Material.WEEPING_VINES_PLANT);
if (type.equals(Material.TWISTING_VINES))
return material.equals(Material.TWISTING_VINES) || material.equals(Material.TWISTING_VINES_PLANT);
return material.equals(type);
}
}

View File

@ -0,0 +1,72 @@
package net.Indyuce.mmocore.experience.source;
import io.lumine.mythic.lib.api.MMOLineConfig;
import io.lumine.mythic.lib.api.event.PlayerAttackEvent;
import io.lumine.mythic.lib.damage.DamagePacket;
import io.lumine.mythic.lib.damage.DamageType;
import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.experience.dispenser.ExperienceDispenser;
import net.Indyuce.mmocore.experience.source.type.SpecificExperienceSource;
import net.Indyuce.mmocore.manager.profession.ExperienceSourceManager;
import org.apache.commons.lang.Validate;
import org.bukkit.event.EventHandler;
import scala.Enumeration;
import java.util.Arrays;
import java.util.Objects;
import java.util.stream.Collectors;
public class DamageDealtExperienceSource extends SpecificExperienceSource<DamageType> {
private final DamageType type;
/**
* Gives experience when a player deals damage of a certain type. If no type is given it will give xp for all
* the damage type. The random value you give correspond to the xp you get per damage dealt.
*/
public DamageDealtExperienceSource(ExperienceDispenser dispenser, MMOLineConfig config) {
super(dispenser, config);
if (!config.contains("type"))
type = null;
else {
String str = config.getString("type").toUpperCase().replace("-", "_");
//Checks if the damage type correspond to a value of the damage type enum
Validate.isTrue(Arrays.stream(DamageType.values()).map(Objects::toString).collect(Collectors.toList()).contains(str),
"Type value not allowed. Type value allowed: magic, physical, weapon, skill, projectile," +
" unarmed, on-hit, minion, dot.");
type = DamageType.valueOf(str);
}
}
@Override
public ExperienceSourceManager<DamageDealtExperienceSource> newManager() {
return new ExperienceSourceManager<DamageDealtExperienceSource>() {
@EventHandler
public void onDamageDealt(PlayerAttackEvent e) {
PlayerData playerData = PlayerData.get(e.getPlayer());
for (DamageDealtExperienceSource source : getSources()) {
double value = 0;
for (DamagePacket packet : e.getDamage().getPackets()) {
for (DamageType damageType : packet.getTypes()) {
if (source.matchesParameter(playerData, damageType))
value += packet.getFinalValue();
}
}
source.giveExperience(playerData, value, null);
}
}
};
}
@Override
public boolean matchesParameter(PlayerData player, DamageType damageType) {
if (type == null)
return true;
else
return type.equals(damageType);
}
}

View File

@ -0,0 +1,72 @@
package net.Indyuce.mmocore.experience.source;
import io.lumine.mythic.lib.api.MMOLineConfig;
import io.lumine.mythic.lib.damage.DamageType;
import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.experience.dispenser.ExperienceDispenser;
import net.Indyuce.mmocore.experience.source.type.SpecificExperienceSource;
import net.Indyuce.mmocore.manager.profession.ExperienceSourceManager;
import org.apache.commons.lang.Validate;
import org.bukkit.OfflinePlayer;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.entity.EntityDamageEvent;
import org.bukkit.scheduler.BukkitRunnable;
import java.util.Arrays;
import java.util.Objects;
import java.util.stream.Collectors;
public class DamageTakenExperienceSource extends SpecificExperienceSource<EntityDamageEvent.DamageCause> {
private final EntityDamageEvent.DamageCause cause;
/**
* Gives experience when a player takes damage from a certain cause. If no cause is given it will give xp for all
* the damage causes. The random value you give correspond to the xp you get per damage taken.
*/
public DamageTakenExperienceSource(ExperienceDispenser dispenser, MMOLineConfig config) {
super(dispenser, config);
if (!config.contains("cause"))
cause = null;
else {
String str = config.getString("cause").toUpperCase().replace("-", "_");
//Checks if the damage type correspond to a value of the damage type enum
Validate.isTrue(Arrays.stream(EntityDamageEvent.DamageCause.values()).map(Objects::toString).collect(Collectors.toList()).contains(str),
"Cause not allowed. Go check at all the Damage Causes in EntityDamageEvent.DamageCause enum.");
cause = EntityDamageEvent.DamageCause.valueOf(str);
}
}
@Override
public ExperienceSourceManager<DamageTakenExperienceSource> newManager() {
return new ExperienceSourceManager<DamageTakenExperienceSource>() {
@EventHandler
public void onDamageTaken(EntityDamageEvent e) {
if (e.getEntity() instanceof Player && !e.getEntity().hasMetadata("NPC")) {
double amount = e.getDamage();
PlayerData playerData = PlayerData.get((OfflinePlayer) e.getEntity());
//We wait 2 tick to check if the player is Dead
new BukkitRunnable() {
@Override
public void run() {
for (DamageTakenExperienceSource source : getSources()) {
if (source.matchesParameter(playerData, e.getCause()))
source.giveExperience(playerData, amount, null);
}
}
}.runTaskLater(MMOCore.plugin, 2);
}
}
};
}
@Override
public boolean matchesParameter(PlayerData player, EntityDamageEvent.DamageCause damageCause) {
if (player.getPlayer().isDead())
return false;
if (cause == null)
return true;
return damageCause.equals(cause);
}
}

View File

@ -0,0 +1,58 @@
package net.Indyuce.mmocore.experience.source;
import io.lumine.mythic.lib.api.MMOLineConfig;
import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.experience.dispenser.ExperienceDispenser;
import net.Indyuce.mmocore.experience.source.type.SpecificExperienceSource;
import net.Indyuce.mmocore.manager.profession.ExperienceSourceManager;
import org.apache.commons.lang3.Validate;
import org.bukkit.Material;
import org.bukkit.OfflinePlayer;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.entity.FoodLevelChangeEvent;
import org.bukkit.inventory.ItemStack;
public class EatExperienceSource extends SpecificExperienceSource<ItemStack> {
private final Material type;
/**
* Gives xp when you eat a certain type of food. If not type is given it will give xp from all the food sources.
* The amount of xp given is the xp per food regenerated.
*/
public EatExperienceSource(ExperienceDispenser dispenser, MMOLineConfig config) {
super(dispenser, config);
if(!config.contains("type"))
type=null;
else {
Material material=Material.valueOf(config.getString("type").toUpperCase().replace("-","_"));
Validate.isTrue(material!=null,"You must precise a valid material!");
type=material;
}
}
@Override
public ExperienceSourceManager<EatExperienceSource> newManager() {
return new ExperienceSourceManager<EatExperienceSource>() {
@EventHandler
public void a(FoodLevelChangeEvent e) {
if (!(e.getEntity() instanceof Player) || e.getEntity().hasMetadata("NPC"))
return;
PlayerData playerData = PlayerData.get((OfflinePlayer) e.getEntity());
for (EatExperienceSource source : getSources()) {
if (source.matchesParameter(playerData, e.getItem()))
source.giveExperience(playerData, e.getFoodLevel(), null);
}
}
};
}
@Override
public boolean matchesParameter(PlayerData player, ItemStack obj) {
if(type==null)
return true;
return type.equals(obj.getType());
}
}

View File

@ -60,7 +60,7 @@ public class EnchantItemExperienceSource extends ExperienceSource<Void> {
double exp = 0;
for (Entry<Enchantment, Integer> entry : applicableEnchants.entrySet())
exp += MMOCore.plugin.enchantManager.getBaseExperience(entry.getKey()) * entry.getValue();
getDispenser().giveExperience(player, (int) exp, event.getEnchantBlock().getLocation(), EXPSource.SOURCE);
getDispenser().giveExperience(player, exp, event.getEnchantBlock().getLocation(), EXPSource.SOURCE);
}
}
};

View File

@ -15,7 +15,7 @@ import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.inventory.ItemStack;
public class MineBlockExperienceSource extends SpecificExperienceSource<Material> {
public final Material material;
private final Material material;
private final boolean silkTouch;
private final boolean crop;

View File

@ -0,0 +1,81 @@
package net.Indyuce.mmocore.experience.source;
import io.lumine.mythic.lib.api.MMOLineConfig;
import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.experience.dispenser.ExperienceDispenser;
import net.Indyuce.mmocore.experience.source.type.SpecificExperienceSource;
import net.Indyuce.mmocore.manager.profession.ExperienceSourceManager;
import org.apache.commons.lang.Validate;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.player.PlayerMoveEvent;
import java.util.Arrays;
import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Collectors;
public class MoveExperienceSource extends SpecificExperienceSource {
private final MovingType type;
public MoveExperienceSource(ExperienceDispenser dispenser, MMOLineConfig config) {
super(dispenser, config);
if (!config.contains("type"))
type = null;
else {
String str = config.getString("type").toUpperCase().replace("-", "_");
//Checks if the damage type correspond to a value of the damage type enum
Validate.isTrue(Arrays.stream(MoveExperienceSource.MovingType.values()).map(Objects::toString).collect(Collectors.toList()).contains(str),
"moving-type value not allowed. Moving type values allowed: sneak, fly, swim, sprint, walk.");
type = MovingType.valueOf(str);
}
}
@Override
public ExperienceSourceManager<MoveExperienceSource> newManager() {
return new ExperienceSourceManager<MoveExperienceSource>() {
@EventHandler
public void onMove(PlayerMoveEvent e) {
double deltax = e.getTo().getBlockX() - e.getFrom().getBlockX();
double deltay = e.getTo().getBlockY() - e.getFrom().getBlockY();
double deltaz = e.getTo().getBlockZ() - e.getFrom().getBlockZ();
if (deltax != 0 && deltay != 0 && deltaz != 0) {
double delta = Math.sqrt(deltax * deltax + deltay * deltay + deltaz * deltaz);
if (e.getPlayer().hasMetadata("NPC"))
return;
Player player = e.getPlayer();
PlayerData playerData = PlayerData.get(player);
for (MoveExperienceSource source : getSources()) {
if (source.matchesParameter(playerData, null)) {
giveExperience(playerData, delta, null);
}
}
}
}
};
}
@Override
public boolean matchesParameter(PlayerData player, Object obj) {
return type == null || type.matches(player.getPlayer());
}
public enum MovingType {
SNEAK(Player::isSneaking),
FLY((p) -> p.isFlying() || p.isGliding()),
SWIM((p) -> p.getLocation().getBlock().isLiquid()),
SPRINT(Player::isSprinting),
WALK((p) -> !p.isSneaking() && !p.isSprinting() && !p.isFlying() && !p.getLocation().getBlock().isLiquid());
private final Function<Player, Boolean> matching;
MovingType(Function<Player, Boolean> matching) {
this.matching = matching;
}
public boolean matches(Player player) {
return !player.isInsideVehicle() && matching.apply(player);
}
}
}

View File

@ -0,0 +1,88 @@
package net.Indyuce.mmocore.experience.source;
import io.lumine.mythic.lib.api.MMOLineConfig;
import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.experience.dispenser.ExperienceDispenser;
import net.Indyuce.mmocore.experience.source.type.SpecificExperienceSource;
import net.Indyuce.mmocore.manager.profession.ExperienceSourceManager;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.scheduler.BukkitRunnable;
import java.util.Objects;
public class PlayExperienceSource extends SpecificExperienceSource {
private final World world;
private final double x1, x2, z1, z2;
private final boolean inCombat;
/**
* Experience source giving the specified amount of xp to all the players online each second in certain world bounds.
* If no bounds are given, it will give the xp to every player online. You can also specifiy if the player
* has to be inCombat or not to get the xp.
*/
public PlayExperienceSource(ExperienceDispenser dispenser, MMOLineConfig config) {
super(dispenser, config);
inCombat = config.getBoolean("in-combat", false);
world = config.contains("world") ? Objects.requireNonNull(Bukkit.getWorld(config.getString("world")), "Could not find world " + config.getString("world")) : null;
if (!config.contains("x1") || !config.contains("x2")) {
x1 = Double.NEGATIVE_INFINITY;
x2 = Double.POSITIVE_INFINITY;
} else {
x1 = Math.min(config.getInt("x1"), config.getInt("x2"));
x2 = Math.max(config.getInt("x1"), config.getInt("x2"));
}
if (!config.contains("z1") || !config.contains("z2")) {
z1 = Double.NEGATIVE_INFINITY;
z2 = Double.POSITIVE_INFINITY;
} else {
z1 = Math.min(config.getInt("z1"), config.getInt("z2"));
z2 = Math.max(config.getInt("z1"), config.getInt("z2"));
}
}
@Override
public ExperienceSourceManager<PlayExperienceSource> newManager() {
return new PlayingExperienceSourceManager();
}
@Override
public boolean matchesParameter(PlayerData player, Object obj) {
if (inCombat && !player.isInCombat())
return false;
if (world == null)
return true;
Location location = player.getPlayer().getLocation();
return location.getWorld().equals(world) && location.getX() > x1 && location.getX() < x2
&& location.getZ() > z1 && location.getZ() < z2;
}
private class PlayingExperienceSourceManager extends ExperienceSourceManager<PlayExperienceSource> {
public PlayingExperienceSourceManager() {
new BukkitRunnable() {
@Override
public void run() {
Bukkit.getOnlinePlayers().forEach((player) -> {
if (!player.hasMetadata("NPC")) {
PlayerData playerData = PlayerData.get(player);
for (PlayExperienceSource source : getSources()) {
if (source.matchesParameter(playerData, null))
giveExperience(playerData, 1, null);
}
}
});
}
}.runTaskTimer(MMOCore.plugin, 0, 20);
}
}
}

View File

@ -0,0 +1,125 @@
package net.Indyuce.mmocore.experience.source;
import io.lumine.mythic.lib.api.MMOLineConfig;
import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.experience.dispenser.ExperienceDispenser;
import net.Indyuce.mmocore.experience.source.type.SpecificExperienceSource;
import net.Indyuce.mmocore.manager.profession.ExperienceSourceManager;
import org.apache.commons.lang.Validate;
import org.bukkit.Location;
import org.bukkit.entity.Arrow;
import org.bukkit.entity.Player;
import org.bukkit.entity.Projectile;
import org.bukkit.entity.Trident;
import org.bukkit.event.EventHandler;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.event.entity.ProjectileHitEvent;
import org.bukkit.event.entity.ProjectileLaunchEvent;
import org.bukkit.scheduler.BukkitRunnable;
import java.util.Arrays;
import java.util.HashMap;
import java.util.function.Function;
import java.util.stream.Collectors;
public class ProjectileExperienceSource extends SpecificExperienceSource<Projectile> {
private final ProjectileType projectileType;
public ProjectileExperienceSource(ExperienceDispenser dispenser, MMOLineConfig config) {
super(dispenser, config);
if (!config.contains("type"))
projectileType = null;
else {
String str = config.getString("type").toUpperCase().replace("-", "_");
Validate.isTrue(Arrays.stream(ProjectileType.values()).map(ProjectileType::toString).collect(Collectors.toList()).contains(str));
projectileType = ProjectileType.valueOf(str);
}
}
@Override
public ExperienceSourceManager<ProjectileExperienceSource> newManager() {
return new ExperienceSourceManager<ProjectileExperienceSource>() {
HashMap<Projectile, Location> projectiles = new HashMap<>();
@EventHandler
public void onHit(ProjectileHitEvent e) {
if (e.getHitBlock() != null && projectiles.containsKey(e.getEntity()))
projectiles.remove(e.getEntity());
}
@EventHandler
public void onDamage(EntityDamageByEntityEvent e) {
if (e.getEntity() instanceof Projectile) {
Projectile projectile = (Projectile) e.getEntity();
if (!projectiles.containsKey(projectile))
return;
if (projectile.getShooter() instanceof Player && !((Player) projectile.getShooter()).hasMetadata("NPC")) {
Player player = (Player) projectile.getShooter();
PlayerData playerData = PlayerData.get(player);
double distance = projectiles.get(projectile).distance(e.getEntity().getLocation());
for (ProjectileExperienceSource source : getSources()) {
if (source.matchesParameter(playerData, projectile))
source.giveExperience(playerData, e.getFinalDamage() * distance, null);
}
}
projectiles.remove(projectile);
}
}
//Mark every arrow with the the location at which it was shot to calculate the distance
@EventHandler
public void onLaunch(ProjectileLaunchEvent e) {
if (e.getEntity().getShooter() instanceof Player) {
Player player = (Player) e.getEntity().getShooter();
if (player.hasMetadata("NPC"))
return;
projectiles.put(e.getEntity(), e.getLocation());
//Remove the projectile 15 s after it was launched
new BukkitRunnable() {
@Override
public void run() {
projectiles.remove(e.getEntity());
}
}.runTaskLater(MMOCore.plugin, 60 * 20L);
}
}
};
}
@Override
public boolean matchesParameter(PlayerData player, Projectile projectile) {
if (projectileType == null)
return true;
return projectileType.matches(projectile);
}
public enum ProjectileType {
ARROW((p) -> p instanceof Arrow),
TRIDENT((p) -> p instanceof Trident);
private final Function<Projectile, Boolean> matching;
ProjectileType(Function<Projectile, Boolean> matching) {
this.matching = matching;
}
public boolean matches(Projectile projectile) {
return matching.apply(projectile);
}
}
}

View File

@ -75,7 +75,7 @@ public class RepairItemExperienceSource extends ExperienceSource<ItemStack> {
*/
double exp = MMOCore.plugin.smithingManager.getBaseExperience(item.getType())
* Math.max(0, ((Damageable) old.getItemMeta()).getDamage() - ((Damageable) item.getItemMeta()).getDamage()) / 100;
getDispenser().giveExperience(data, (int) exp, null, EXPSource.SOURCE);
getDispenser().giveExperience(data, exp, data.getPlayer().getLocation(), EXPSource.SOURCE);
}
}
}

View File

@ -0,0 +1,61 @@
package net.Indyuce.mmocore.experience.source;
import io.lumine.mythic.lib.api.MMOLineConfig;
import net.Indyuce.mmocore.api.event.PlayerResourceUpdateEvent;
import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.api.player.profess.resource.PlayerResource;
import net.Indyuce.mmocore.experience.dispenser.ExperienceDispenser;
import net.Indyuce.mmocore.experience.source.type.SpecificExperienceSource;
import net.Indyuce.mmocore.manager.profession.ExperienceSourceManager;
import org.apache.commons.lang.Validate;
import org.bukkit.event.EventHandler;
import java.util.Arrays;
import java.util.Objects;
import java.util.stream.Collectors;
public class ResourceExperienceSource extends SpecificExperienceSource<PlayerResource> {
private final PlayerResource resource;
/**
* Gives experience when the player uses a specific resoure. If no resource is precised it will trigger for
* mana, stamina and stellium. The amount specified si the xp given per resource consummed.
*/
public ResourceExperienceSource(ExperienceDispenser dispenser, MMOLineConfig config) {
super(dispenser, config);
if (!config.contains("resource"))
resource = null;
else {
String str = config.getString("resource").toUpperCase().replace("-", "_");
Validate.isTrue(str.equals("MANA") || str.equals("STELLIUM") || str.equals("STAMINA"),
"ResourceExperienceSource problem: The resource can only be mana, stamina or STELLIUM");
resource = PlayerResource.valueOf(str);
}
}
@Override
public ExperienceSourceManager<ResourceExperienceSource> newManager() {
return new ExperienceSourceManager<ResourceExperienceSource>() {
@EventHandler
public void onResource(PlayerResourceUpdateEvent e) {
if (e.getPlayer().hasMetadata("NPC"))
return;
PlayerData playerData = PlayerData.get(e.getPlayer());
if(e.getAmount()<0)
for (ResourceExperienceSource source : getSources()) {
if (source.matchesParameter(playerData, e.getResource()))
source.giveExperience(playerData, -e.getAmount(), null);
}
}
};
}
@Override
public boolean matchesParameter(PlayerData player, PlayerResource obj) {
if (resource == null)
return !obj.equals(PlayerResource.HEALTH);
return resource.equals(obj);
}
}

View File

@ -0,0 +1,74 @@
package net.Indyuce.mmocore.experience.source;
import io.lumine.mythic.lib.api.MMOLineConfig;
import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.experience.dispenser.ExperienceDispenser;
import net.Indyuce.mmocore.experience.source.type.SpecificExperienceSource;
import net.Indyuce.mmocore.manager.profession.ExperienceSourceManager;
import org.apache.commons.lang.Validate;
import org.bukkit.Bukkit;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.event.EventHandler;
import org.bukkit.event.player.PlayerMoveEvent;
import java.util.Arrays;
import java.util.Objects;
import java.util.stream.Collectors;
public class RideExperienceSource extends SpecificExperienceSource<EntityType> {
private final EntityType type;
/**
* Gives experience when a player moves riding a certain entity. If no entity type is given it will give xp if you move
* while riding an entity whatever it is.
* The random value you give correspond to the xp you get per block travelled while riding.
*/
public RideExperienceSource(ExperienceDispenser dispenser, MMOLineConfig config) {
super(dispenser, config);
if (!config.contains("type"))
type = null;
else {
String str = config.getString("type").toUpperCase().replace("-", "_");
Validate.isTrue(Arrays.stream(EntityType.values()).map(Objects::toString).collect(Collectors.toList()).contains(str),
"The type must correspond to an entity that exist in the game.");
type = EntityType.valueOf(str);
}
}
@Override
public ExperienceSourceManager<RideExperienceSource> newManager() {
return new ExperienceSourceManager<RideExperienceSource>() {
@EventHandler
public void onRide(PlayerMoveEvent e) {
if (e.getPlayer().isInsideVehicle()) {
double deltax = e.getTo().getBlockX() - e.getFrom().getBlockX();
double deltay = e.getTo().getBlockY() - e.getFrom().getBlockY();
double deltaz = e.getTo().getBlockZ() - e.getFrom().getBlockZ();
if (deltax != 0 && deltay != 0 && deltaz != 0) {
double delta = Math.sqrt(deltax * deltax + deltay * deltay + deltaz * deltaz);
if (e.getPlayer().hasMetadata("NPC"))
return;
PlayerData playerData = PlayerData.get(e.getPlayer());
Entity vehicle = e.getPlayer().getVehicle();
for (RideExperienceSource source : getSources()) {
if (source.matchesParameter(playerData, vehicle.getType()))
giveExperience(playerData, e.getFrom().distance(e.getTo()), null);
}
}
}
}
};
}
@Override
public boolean matchesParameter(PlayerData player, EntityType obj) {
if (type == null)
return true;
return type.equals(obj);
}
}

View File

@ -0,0 +1,43 @@
package net.Indyuce.mmocore.experience.source;
import io.lumine.mythic.lib.api.MMOLineConfig;
import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.api.util.MMOCoreUtils;
import net.Indyuce.mmocore.experience.dispenser.ExperienceDispenser;
import net.Indyuce.mmocore.experience.source.type.SpecificExperienceSource;
import net.Indyuce.mmocore.manager.profession.ExperienceSourceManager;
import org.bukkit.OfflinePlayer;
import org.bukkit.entity.Player;
import org.bukkit.entity.Wolf;
import org.bukkit.event.EventHandler;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
public class TameExperienceSource extends SpecificExperienceSource {
public TameExperienceSource(ExperienceDispenser dispenser, MMOLineConfig config) {
super(dispenser, config);
}
@Override
public ExperienceSourceManager<TameExperienceSource> newManager() {
return new ExperienceSourceManager<TameExperienceSource>() {
@EventHandler
public void onWolfHit(EntityDamageByEntityEvent e) {
if(e.getDamager() instanceof Wolf) {
Wolf wolf= (Wolf) e.getDamager();
if(wolf.getOwner() instanceof Player &&!((Player) wolf.getOwner()).hasMetadata("NPC")) {
PlayerData playerData=PlayerData.get((OfflinePlayer) wolf.getOwner());
for(TameExperienceSource source:getSources()) {
source.giveExperience(playerData,e.getDamage(), MMOCoreUtils.getCenterLocation(e.getEntity()));
}
}
}
}
};
}
@Override
public boolean matchesParameter(PlayerData player, Object obj) {
return false;
}
}

View File

@ -5,11 +5,13 @@ import net.Indyuce.mmocore.experience.EXPSource;
import net.Indyuce.mmocore.experience.dispenser.ExperienceDispenser;
import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.api.util.math.formula.RandomAmount;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.jetbrains.annotations.Nullable;
public abstract class SpecificExperienceSource<T> extends ExperienceSource<T> {
private final RandomAmount amount;
double counter = 0;
/**
* Used to register experience sources with SPECIFIC experience outputs.
@ -27,8 +29,8 @@ public abstract class SpecificExperienceSource<T> extends ExperienceSource<T> {
return amount;
}
public int rollAmount() {
return amount.calculateInt();
public double rollAmount() {
return amount.calculate();
}
/**

View File

@ -13,6 +13,7 @@ import net.Indyuce.mmocore.gui.api.item.InventoryItem;
import net.Indyuce.mmocore.gui.api.item.Placeholders;
import net.Indyuce.mmocore.gui.api.item.SimplePlaceholderItem;
import net.Indyuce.mmocore.manager.SoundManager;
import net.Indyuce.mmocore.player.stats.StatInfo;
import org.bukkit.Bukkit;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.event.inventory.InventoryClickEvent;
@ -66,8 +67,9 @@ public class AttributeView extends EditableInventory {
holders.register("current", total);
holders.register("attribute_points", inv.getPlayerData().getAttributePoints());
attribute.getBuffs().forEach(buff -> {
holders.register("buff_" + buff.getStat().toLowerCase(), buff.getValue());
holders.register("total_" + buff.getStat().toLowerCase(), buff.multiply(total).getValue());
StatInfo info = StatInfo.valueOf(buff.getStat());
holders.register("buff_" + buff.getStat().toLowerCase(), info.format(buff.getValue()));
holders.register("total_" + buff.getStat().toLowerCase(), info.format(buff.multiply(total).getValue()));
});
return holders;
}

View File

@ -1,14 +1,15 @@
package net.Indyuce.mmocore.gui;
import io.lumine.mythic.lib.UtilityMethods;
import io.lumine.mythic.lib.api.stat.modifier.StatModifier;
import io.lumine.mythic.lib.version.VersionMaterial;
import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.experience.Booster;
import net.Indyuce.mmocore.experience.Profession;
import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.api.player.attribute.PlayerAttribute;
import net.Indyuce.mmocore.api.player.stats.StatType;
import net.Indyuce.mmocore.player.stats.StatInfo;
import net.Indyuce.mmocore.api.util.math.format.DelayFormat;
import net.Indyuce.mmocore.experience.Booster;
import net.Indyuce.mmocore.experience.Profession;
import net.Indyuce.mmocore.gui.api.EditableInventory;
import net.Indyuce.mmocore.gui.api.GeneratedInventory;
import net.Indyuce.mmocore.gui.api.item.InventoryItem;
@ -18,10 +19,13 @@ import net.Indyuce.mmocore.party.AbstractParty;
import org.apache.commons.lang.Validate;
import org.bukkit.ChatColor;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.SkullMeta;
import java.util.Objects;
public class PlayerStats extends EditableInventory {
public PlayerStats() {
super("player-stats");
@ -78,7 +82,7 @@ public class PlayerStats extends EditableInventory {
Placeholders holders = new Placeholders();
net.Indyuce.mmocore.api.player.stats.PlayerStats stats = inv.getPlayerData().getStats();
double ratio = (double) inv.getPlayerData().getCollectionSkills().getExperience(profession)
double ratio = inv.getPlayerData().getCollectionSkills().getExperience(profession)
/ (double) inv.getPlayerData().getCollectionSkills().getLevelUpExperience(profession);
String bar = "" + ChatColor.BOLD;
@ -91,9 +95,9 @@ public class PlayerStats extends EditableInventory {
holders.register("level", "" + inv.getPlayerData().getCollectionSkills().getLevel(profession));
holders.register("xp", inv.getPlayerData().getCollectionSkills().getExperience(profession));
holders.register("percent", decimal.format(ratio * 100));
for (StatType stat : StatType.values())
if (stat.matches(profession))
holders.register(stat.name().toLowerCase(), stat.format(stats.getStat(stat)));
for (StatInfo stat : MMOCore.plugin.statManager.getLoaded())
if (Objects.equals(stat.profession, profession))
holders.register(stat.name.toLowerCase(), stat.format(stats.getStat(stat.name)));
return holders;
}
@ -113,21 +117,35 @@ public class PlayerStats extends EditableInventory {
@Override
public Placeholders getPlaceholders(GeneratedInventory inv, int n) {
return new Placeholders() {
final net.Indyuce.mmocore.api.player.stats.PlayerStats stats = inv.getPlayerData().getStats();
net.Indyuce.mmocore.api.player.stats.PlayerStats stats = inv.getPlayerData().getStats();
Placeholders holders = new Placeholders();
public String apply(Player player, String str) {
while (str.contains("{") && str.substring(str.indexOf("{")).contains("}")) {
String holder = str.substring(str.indexOf("{") + 1, str.indexOf("}"));
String replaced;
for (StatType stat : StatType.values()) {
double base = stats.getBase(stat), total = stats.getStat(stat), extra = total - base;
holders.register(stat.name().toLowerCase(), stat.format(total));
holders.register(stat.name().toLowerCase() + "_base", stat.format(base));
holders.register(stat.name().toLowerCase() + "_extra", stat.format(extra));
}
if (holder.endsWith("_base")) {
StatInfo info = StatInfo.valueOf(UtilityMethods.enumName(holder.substring(0, holder.length() - 5)));
replaced = info.format(stats.getBase(info.name));
} else if (holder.endsWith("_extra")) {
StatInfo info = StatInfo.valueOf(UtilityMethods.enumName(holder.substring(0, holder.length() - 5)));
replaced = info.format(stats.getStat(info.name) - stats.getBase(info.name));
} else if (holder.startsWith("attribute_")) {
PlayerAttribute attr = MMOCore.plugin.attributeManager.get(holder.substring(10).replace("_", "-").toLowerCase());
replaced = String.valueOf(inv.getPlayerData().getAttributes().getAttribute(attr));
} else {
StatInfo info = StatInfo.valueOf(UtilityMethods.enumName(holder));
replaced = info.format(stats.getStat(info.name));
}
for (PlayerAttribute attribute : MMOCore.plugin.attributeManager.getAll())
holders.register("attribute_" + attribute.getId().replace("-", "_"), inv.getPlayerData().getAttributes().getAttribute(attribute));
str = str.replace("{" + holder + "}", replaced);
}
return holders;
// External placeholders
return MMOCore.plugin.placeholderParser.parse(player, str);
}
};
}
};

View File

@ -13,7 +13,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 org.apache.commons.lang.Validate;
import org.bukkit.ChatColor;
import org.bukkit.Material;
import org.bukkit.Sound;
@ -38,9 +37,6 @@ public class SkillList extends EditableInventory {
if (function.equals("skill"))
return new SkillItem(config);
if (function.equals("switch"))
return new SwitchItem(config);
if (function.equals("level"))
return new LevelItem(config);
@ -49,7 +45,7 @@ public class SkillList extends EditableInventory {
@Override
public Placeholders getPlaceholders(SkillViewerInventory inv, int n) {
RegisteredSkill selected = inv.selected.getSkill();
RegisteredSkill selected = inv.selected == null ? null : inv.selected.getSkill();
Placeholders holders = new Placeholders();
holders.register("skill_caps", selected.getName().toUpperCase());
@ -58,11 +54,6 @@ public class SkillList extends EditableInventory {
return holders;
}
@Override
public boolean canDisplay(SkillViewerInventory inv) {
return !inv.binding;
}
};
if (function.equals("slot"))
@ -74,7 +65,7 @@ public class SkillList extends EditableInventory {
@Override
public Placeholders getPlaceholders(SkillViewerInventory inv, int n) {
RegisteredSkill selected = inv.selected.getSkill();
RegisteredSkill selected = inv.selected == null ? null : inv.selected.getSkill();
RegisteredSkill skill = inv.getPlayerData().hasSkillBound(n) ? inv.getPlayerData().getBoundSkill(n).getSkill() : null;
Placeholders holders = new Placeholders();
@ -82,7 +73,7 @@ public class SkillList extends EditableInventory {
holders.register("skill", skill == null ? none : skill.getName());
holders.register("index", "" + (n + 1));
holders.register("slot", MMOCoreUtils.intToRoman(n + 1));
holders.register("selected", selected.getName());
holders.register("selected", selected == null ? none : selected.getName());
return holders;
}
@ -102,16 +93,29 @@ public class SkillList extends EditableInventory {
return item;
}
@Override
public boolean canDisplay(SkillViewerInventory inv) {
return inv.binding;
}
@Override
public boolean hasDifferentDisplay() {
return true;
}
};
if (function.equals("previous"))
return new SimplePlaceholderItem<SkillViewerInventory>(config) {
@Override
public boolean canDisplay(SkillViewerInventory inv) {
return inv.page > 0;
}
};
if (function.equals("next")) {
return new SimplePlaceholderItem<SkillViewerInventory>(config) {
@Override
public boolean canDisplay(SkillViewerInventory inv) {
final int perPage = inv.skillSlots.size();
return inv.page < (inv.skills.size() - 1) / perPage;
}
};
}
return new SimplePlaceholderItem(config);
}
@ -120,30 +124,6 @@ public class SkillList extends EditableInventory {
return new SkillViewerInventory(data, this);
}
public class SwitchItem extends SimplePlaceholderItem<SkillViewerInventory> {
private final SimplePlaceholderItem binding, upgrading;
public SwitchItem(ConfigurationSection config) {
super(config);
Validate.isTrue(config.contains("binding"), "Config must have 'binding'");
Validate.isTrue(config.contains("upgrading"), "Config must have 'upgrading'");
binding = new SimplePlaceholderItem(config.getConfigurationSection("binding"));
upgrading = new SimplePlaceholderItem(config.getConfigurationSection("upgrading"));
}
@Override
public ItemStack display(SkillViewerInventory inv, int n) {
return inv.binding ? upgrading.display(inv) : binding.display(inv);
}
@Override
public boolean canDisplay(SkillViewerInventory inv) {
return true;
}
}
public class LevelItem extends InventoryItem<SkillViewerInventory> {
private final int offset;
@ -193,20 +173,11 @@ public class SkillList extends EditableInventory {
public Placeholders getPlaceholders(SkillViewerInventory inv, int n) {
return new Placeholders();
}
@Override
public boolean canDisplay(SkillViewerInventory inv) {
return !inv.binding;
}
}
public class SkillItem extends InventoryItem<SkillViewerInventory> {
private final int selectedSkillSlot;
public SkillItem(ConfigurationSection config) {
super(Material.BARRIER, config);
selectedSkillSlot = config.getInt("selected-slot");
}
@Override
@ -217,15 +188,17 @@ public class SkillList extends EditableInventory {
@Override
public ItemStack display(SkillViewerInventory inv, int n) {
/*
* calculate placeholders
*/
ClassSkill skill = inv.skills.get(mod(n + inv.getPlayerData().skillGuiDisplayOffset, inv.skills.size()));
// Calculate placeholders
int index = n + inv.skillSlots.size() * inv.page;
if (index >= inv.skills.size())
return new ItemStack(Material.AIR);
ClassSkill skill = inv.skills.get(index);
Placeholders holders = getPlaceholders(inv.getPlayerData(), skill);
List<String> lore = new ArrayList<>(getLore());
int index = lore.indexOf("{lore}");
index = lore.indexOf("{lore}");
lore.remove(index);
List<String> skillLore = skill.calculateLore(inv.getPlayerData());
for (int j = 0; j < skillLore.size(); j++)
@ -238,9 +211,7 @@ public class SkillList extends EditableInventory {
for (int j = 0; j < lore.size(); j++)
lore.set(j, ChatColor.GRAY + holders.apply(inv.getPlayer(), lore.get(j)));
/*
* generate item
*/
// Generate item
ItemStack item = skill.getSkill().getIcon();
ItemMeta meta = item.getItemMeta();
meta.setDisplayName(holders.apply(inv.getPlayer(), getName()));
@ -272,8 +243,9 @@ public class SkillList extends EditableInventory {
private final List<Integer> skillSlots;
private final List<Integer> slotSlots;
private boolean binding;
//The skill the player Selected
private ClassSkill selected;
private int page = 0;
public SkillViewerInventory(PlayerData playerData, EditableInventory editable) {
super(playerData, editable);
@ -281,24 +253,23 @@ public class SkillList extends EditableInventory {
skills = new ArrayList<>(playerData.getProfess().getSkills());
skillSlots = getEditable().getByFunction("skill").getSlots();
slotSlots = getEditable().getByFunction("slot").getSlots();
selected = skills.get(page * skillSlots.size());
}
@Override
public String calculateName() {
return getName();
return getName().replace("{skill}", selected.getSkill().getName());
}
@Override
public void open() {
int selectedSkillSlot = ((SkillItem) getEditable().getByFunction("skill")).selectedSkillSlot;
selected = skills.get(mod(selectedSkillSlot + playerData.skillGuiDisplayOffset, skills.size()));
super.open();
}
@Override
public void whenClicked(InventoryClickEvent event, InventoryItem item) {
/*
if (skillSlots.contains(event.getRawSlot())
&& event.getRawSlot() != ((SkillItem) getEditable().getByFunction("skill")).selectedSkillSlot) {
player.playSound(player.getLocation(), Sound.UI_BUTTON_CLICK, 1, 2);
@ -306,24 +277,26 @@ public class SkillList extends EditableInventory {
open();
return;
}
*/
if (item.getFunction().equals("skill")) {
int index = skillSlots.size() * page + skillSlots.indexOf(event.getRawSlot());
player.playSound(player.getLocation(), Sound.UI_BUTTON_CLICK, 1, 2);
selected = skills.get(index);
open();
return;
}
if (item.getFunction().equals("previous")) {
player.playSound(player.getLocation(), Sound.UI_BUTTON_CLICK, 1, 2);
playerData.skillGuiDisplayOffset = (playerData.skillGuiDisplayOffset - 1) % skills.size();
page--;
open();
return;
}
if (item.getFunction().equals("next")) {
player.playSound(player.getLocation(), Sound.UI_BUTTON_CLICK, 1, 2);
playerData.skillGuiDisplayOffset = (playerData.skillGuiDisplayOffset + 1) % skills.size();
open();
return;
}
if (item.getFunction().equals("switch")) {
player.playSound(player.getLocation(), Sound.UI_BUTTON_CLICK, 1, 2);
binding = !binding;
page++;
open();
return;
}
@ -331,51 +304,50 @@ public class SkillList extends EditableInventory {
/*
* binding or unbinding skills.
*/
if (binding) {
for (int index = 0; index < slotSlots.size(); index++) {
int slot = slotSlots.get(index);
if (event.getRawSlot() == slot) {
if (item.getFunction().equals("slot")) {
int index = slotSlots.indexOf(event.getRawSlot());
// unbind if there is a current spell.
if (event.getAction() == InventoryAction.PICKUP_HALF) {
if (!playerData.hasSkillBound(index)) {
MMOCore.plugin.configManager.getSimpleMessage("no-skill-bound").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 (selected.getSkill().getTrigger().isPassive()) {
MMOCore.plugin.configManager.getSimpleMessage("not-active-skill").send(player);
player.playSound(player.getLocation(), Sound.ENTITY_VILLAGER_NO, 1, 2);
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;
}
player.playSound(player.getLocation(), Sound.ENTITY_EXPERIENCE_ORB_PICKUP, 1, 2);
playerData.setBoundSkill(index, selected);
open();
// unbind if there is a current spell.
if (event.getAction() == InventoryAction.PICKUP_HALF) {
if (!playerData.hasSkillBound(index)) {
MMOCore.plugin.configManager.getSimpleMessage("no-skill-bound").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;
}
/*
* upgrading a player skill
*/
} else if (item.getFunction().equals("upgrade")) {
if (selected == null)
return;
if (selected.getSkill().getTrigger().isPassive()) {
MMOCore.plugin.configManager.getSimpleMessage("not-active-skill").send(player);
player.playSound(player.getLocation(), Sound.ENTITY_VILLAGER_NO, 1, 2);
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;
}
player.playSound(player.getLocation(), Sound.ENTITY_EXPERIENCE_ORB_PICKUP, 1, 2);
playerData.setBoundSkill(index, selected);
open();
return;
}
/*
* upgrading a player skill
*/
if (item.getFunction().equals("upgrade")) {
if (!playerData.hasSkillUnlocked(selected)) {
MMOCore.plugin.configManager.getSimpleMessage("not-unlocked-skill").send(player);
player.playSound(player.getLocation(), Sound.ENTITY_VILLAGER_NO, 1, 2);
@ -402,6 +374,7 @@ public class SkillList extends EditableInventory {
open();
}
}
}
private int mod(int x, int n) {

View File

@ -1,7 +1,5 @@
package net.Indyuce.mmocore.gui;
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.player.PlayerActivity;
import net.Indyuce.mmocore.api.player.PlayerData;
@ -10,18 +8,24 @@ import net.Indyuce.mmocore.gui.api.GeneratedInventory;
import net.Indyuce.mmocore.gui.api.item.InventoryItem;
import net.Indyuce.mmocore.gui.api.item.Placeholders;
import net.Indyuce.mmocore.gui.api.item.SimplePlaceholderItem;
import net.Indyuce.mmocore.waypoint.CostType;
import net.Indyuce.mmocore.waypoint.Waypoint;
import net.Indyuce.mmocore.waypoint.WaypointOption;
import net.Indyuce.mmocore.waypoint.WaypointPath;
import org.apache.commons.lang.Validate;
import org.bukkit.ChatColor;
import org.bukkit.Material;
import org.bukkit.NamespacedKey;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.persistence.PersistentDataContainer;
import org.bukkit.persistence.PersistentDataType;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Objects;
import java.util.Map;
public class WaypointViewer extends EditableInventory {
public WaypointViewer() {
@ -65,7 +69,7 @@ public class WaypointViewer extends EditableInventory {
public class WaypointItem extends SimplePlaceholderItem<WaypointViewerInventory> {
private final SimplePlaceholderItem noWaypoint, locked;
private final WaypointItemHandler availWaypoint, notLinked, notDynamic, noStellium;
private final WaypointItemHandler availWaypoint, noStellium, notLinked, notDynamic, currentWayPoint;
public WaypointItem(ConfigurationSection config) {
super(Material.BARRIER, config);
@ -74,15 +78,17 @@ public class WaypointViewer extends EditableInventory {
Validate.notNull(config.getConfigurationSection("locked"), "Could not load 'locked' config");
Validate.notNull(config.getConfigurationSection("not-a-destination"), "Could not load 'not-a-destination' config");
Validate.notNull(config.getConfigurationSection("not-dynamic"), "Could not load 'not-dynamic' config");
Validate.notNull(config.getConfigurationSection("current-waypoint"), "Could not load 'current-waypoint' config");
Validate.notNull(config.getConfigurationSection("not-enough-stellium"), "Could not load 'not-enough-stellium' config");
Validate.notNull(config.getConfigurationSection("display"), "Could not load 'display' config");
noWaypoint = new SimplePlaceholderItem(config.getConfigurationSection("no-waypoint"));
locked = new SimplePlaceholderItem(config.getConfigurationSection("locked"));
notLinked = new WaypointItemHandler(config.getConfigurationSection("not-a-destination"));
notDynamic = new WaypointItemHandler(config.getConfigurationSection("not-dynamic"));
noStellium = new WaypointItemHandler(config.getConfigurationSection("not-enough-stellium"));
availWaypoint = new WaypointItemHandler(config.getConfigurationSection("display"));
notLinked = new WaypointItemHandler(config.getConfigurationSection("not-a-destination"), true);
notDynamic = new WaypointItemHandler(config.getConfigurationSection("not-dynamic"), true);
currentWayPoint = new WaypointItemHandler(config.getConfigurationSection("current-waypoint"), true);
noStellium = new WaypointItemHandler(config.getConfigurationSection("not-enough-stellium"), false);
availWaypoint = new WaypointItemHandler(config.getConfigurationSection("display"), false);
}
@Override
@ -99,19 +105,22 @@ public class WaypointViewer extends EditableInventory {
// Locked waypoint?
Waypoint waypoint = inv.waypoints.get(index);
if (inv.current != null && inv.current.equals(waypoint))
return currentWayPoint.display(inv, n);
if (!inv.getPlayerData().hasWaypoint(waypoint))
return locked.display(inv, n);
// Waypoints are not linked
if (inv.current != null && !inv.current.hasDestination(waypoint))
if (inv.current != null && !inv.paths.containsKey(waypoint))
return notLinked.display(inv, n);
// Not dynamic waypoint
if (inv.current == null && !waypoint.hasOption(WaypointOption.DYNAMIC))
if (inv.current == null && !inv.paths.containsKey(waypoint))
return notDynamic.display(inv, n);
// Stellium cost
if (waypoint.getCost(inv.current == null ? CostType.DYNAMIC_USE : CostType.NORMAL_USE) > inv.getPlayerData().getStellium())
//Normal cost
if (inv.paths.get(waypoint).getCost() > inv.getPlayerData().getStellium())
return noStellium.display(inv, n);
return availWaypoint.display(inv, n);
@ -119,8 +128,11 @@ public class WaypointViewer extends EditableInventory {
}
public class WaypointItemHandler extends InventoryItem<WaypointViewerInventory> {
public WaypointItemHandler(ConfigurationSection config) {
private final boolean onlyName;
public WaypointItemHandler(ConfigurationSection config, boolean onlyName) {
super(config);
this.onlyName = onlyName;
}
@Override
@ -129,7 +141,21 @@ public class WaypointViewer extends EditableInventory {
// If a player can teleport to another waypoint given his location
Waypoint waypoint = inv.waypoints.get(inv.page * inv.getEditable().getByFunction("waypoint").getSlots().size() + n);
return NBTItem.get(disp).addTag(new ItemTag("waypointId", waypoint.getId())).toItem();
ItemMeta meta = disp.getItemMeta();
// Add waypoint lore if not empty
if (!waypoint.getLore().isEmpty()) {
List<String> lore = meta.getLore();
Placeholders placeholders = new Placeholders();
for (String str : waypoint.getLore())
lore.add(0, ChatColor.GRAY + placeholders.apply(inv.getPlayer(), str));
meta.setLore(lore);
}
PersistentDataContainer container = meta.getPersistentDataContainer();
container.set(new NamespacedKey(MMOCore.plugin, "waypointId"), PersistentDataType.STRING, waypoint.getId());
disp.setItemMeta(meta);
return disp;
}
@Override
@ -138,9 +164,12 @@ public class WaypointViewer extends EditableInventory {
Waypoint waypoint = inv.waypoints.get(inv.page * inv.getByFunction("waypoint").getSlots().size() + n);
holders.register("name", waypoint.getName());
holders.register("current_cost", decimal.format(waypoint.getCost(inv.waypointCostType)));
holders.register("normal_cost", decimal.format(waypoint.getCost(CostType.NORMAL_USE)));
holders.register("dynamic_cost", decimal.format(waypoint.getCost(CostType.DYNAMIC_USE)));
if (!onlyName) {
holders.register("current_cost", inv.paths.get(waypoint).getCost());
holders.register("normal_cost", decimal.format(inv.paths.containsKey(waypoint) ? inv.paths.get(waypoint).getCost() : Double.POSITIVE_INFINITY));
holders.register("dynamic_cost", decimal.format(waypoint.getDynamicCost()));
holders.register("intermediary_waypoints", inv.paths.containsKey(waypoint) ? inv.paths.get(waypoint).displayIntermediaryWayPoints(inv.isDynamicUse()) : "None");
}
return holders;
}
@ -148,8 +177,9 @@ public class WaypointViewer extends EditableInventory {
public class WaypointViewerInventory extends GeneratedInventory {
private final List<Waypoint> waypoints = new ArrayList<>(MMOCore.plugin.waypointManager.getAll());
@Nullable
private final Waypoint current;
private final CostType waypointCostType;
private final Map<Waypoint, WaypointPath> paths = new HashMap<>();
private int page;
@ -157,7 +187,29 @@ public class WaypointViewer extends EditableInventory {
super(playerData, editable);
this.current = current;
this.waypointCostType = current == null ? CostType.DYNAMIC_USE : CostType.NORMAL_USE;
if (current != null)
for (WaypointPath pathInfo : current.getAllPath())
paths.put(pathInfo.getFinalWaypoint(), pathInfo);
if (current == null) {
//Iterate through all the dynamic points and find all the points it is linked to and the path
HashMap<Waypoint, Double> dynamicPoints = new HashMap<>();
//We first check all the dynamic waypoints
for (Waypoint waypoint : waypoints) {
if (waypoint.mayBeUsedDynamically(playerData.getPlayer())) {
paths.put(waypoint, new WaypointPath(waypoint, waypoint.getDynamicCost()));
dynamicPoints.put(waypoint, waypoint.getDynamicCost());
}
}
for (Waypoint source : dynamicPoints.keySet()) {
for (WaypointPath target : source.getAllPath()) {
if (!paths.containsKey(target.getFinalWaypoint()) || paths.get(target.getFinalWaypoint()).getCost() > target.getCost() + dynamicPoints.get(source)) {
paths.put(target.getFinalWaypoint(), target.addCost(dynamicPoints.get(source)));
}
}
}
}
}
@Override
@ -165,6 +217,10 @@ public class WaypointViewer extends EditableInventory {
return getName();
}
public boolean isDynamicUse() {
return current == null;
}
@Override
public void whenClicked(InventoryClickEvent event, InventoryItem item) {
if (item.getFunction().equals("next")) {
@ -180,7 +236,10 @@ public class WaypointViewer extends EditableInventory {
}
if (item.getFunction().equals("waypoint")) {
String tag = NBTItem.get(event.getCurrentItem()).getString("waypointId");
PersistentDataContainer container = event.getCurrentItem().getItemMeta().getPersistentDataContainer();
String tag = container.has(new NamespacedKey(MMOCore.plugin, "waypointId"), PersistentDataType.STRING) ?
container.get(new NamespacedKey(MMOCore.plugin, "waypointId"), PersistentDataType.STRING) : "";
if (tag.equals(""))
return;
@ -198,20 +257,20 @@ public class WaypointViewer extends EditableInventory {
}
// Waypoint does not have target as destination
if (current != null && !current.hasDestination(waypoint)) {
if (current != null && current.getPath(waypoint) == null) {
MMOCore.plugin.configManager.getSimpleMessage("cannot-teleport-to").send(player);
return;
}
// Not dynamic waypoint
if (current == null && !waypoint.hasOption(WaypointOption.DYNAMIC)) {
if (current == null && !paths.containsKey(waypoint)) {
MMOCore.plugin.configManager.getSimpleMessage("not-dynamic-waypoint").send(player);
return;
}
// Stellium cost
CostType costType = current == null ? CostType.DYNAMIC_USE : CostType.NORMAL_USE;
double left = waypoint.getCost(costType) - playerData.getStellium();
double withdraw = paths.get(waypoint).getCost();
double left = withdraw - playerData.getStellium();
if (left > 0) {
MMOCore.plugin.configManager.getSimpleMessage("not-enough-stellium", "more", decimal.format(left)).send(player);
return;
@ -221,7 +280,8 @@ public class WaypointViewer extends EditableInventory {
return;
player.closeInventory();
playerData.warp(waypoint, costType);
playerData.warp(waypoint, withdraw);
}
}
}

View File

@ -59,7 +59,7 @@ public abstract class GeneratedInventory extends PluginInventory {
@Override
public Inventory getInventory() {
Inventory inv = Bukkit.createInventory(this, editable.getSlots(), MythicLib.plugin.parseColors(calculateName()));
Inventory inv = Bukkit.createInventory(this, editable.getSlots(), MythicLib.plugin.getPlaceholderParser().parse(getPlayer(), calculateName()));
for (InventoryItem item : editable.getItems())
if (item.canDisplay(this))

View File

@ -11,7 +11,7 @@ import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.api.util.MMOCoreUtils;
import net.Indyuce.mmocore.experience.source.MineBlockExperienceSource;
import net.Indyuce.mmocore.loot.LootBuilder;
import net.Indyuce.mmocore.loot.droptable.condition.ConditionInstance;
import net.Indyuce.mmocore.loot.chest.condition.ConditionInstance;
import org.bukkit.*;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;

View File

@ -52,7 +52,7 @@ public class ClassTriggers implements Listener {
public void onAttack(PlayerAttackEvent event) {
for (Map.Entry<DamageType, ClassTriggerType> entry : damageTriggers.entrySet())
if (event.getDamage().hasType(entry.getKey()))
applyTriggers(event.getPlayer(), entry.getValue()); //, () -> new TriggerMetadata(event.getAttack(), event.getEntity())
applyTriggers(event.getPlayer(), entry.getValue(), () -> new TriggerMetadata(event.getAttack(), event.getEntity()));
}
@EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR)
@ -88,6 +88,16 @@ public class ClassTriggers implements Listener {
return applyTriggers(PlayerData.get(player), type, triggerMetaProvider);
}
/**
* Apply class shortcut skills from a specific class trigger type.
*
* @param player Player triggering
* @param type Trigger type
* @param triggerMetaProvider Small optimization: if no shortcut skill is found
* with the corresponding trigger type, trigger meta
* is not calculated which saves computations
* @return Skill result or null if no shortcut skill was cast
*/
@Nullable
private SkillResult applyTriggers(PlayerData player, ClassTriggerType type, Provider<TriggerMetadata> triggerMetaProvider) {
ClassTrigger trigger = player.getProfess().getClassTrigger(type);

View File

@ -1,22 +1,36 @@
package net.Indyuce.mmocore.listener;
import org.bukkit.block.Chest;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.inventory.InventoryCloseEvent;
import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.loot.chest.LootChest;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.block.Chest;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.event.inventory.InventoryCloseEvent;
public class LootableChestsListener implements Listener {
@EventHandler
public void a(InventoryCloseEvent event) {
if (!(event.getInventory().getHolder() instanceof Chest))
return;
Chest chest = (Chest) event.getInventory().getHolder();
LootChest lootChest = MMOCore.plugin.lootChests.getChest(chest.getLocation());
if (lootChest != null)
lootChest.expire(true);
}
@EventHandler
public void expireOnClose(InventoryCloseEvent event) {
if (!(event.getInventory().getHolder() instanceof Chest))
return;
Chest chest = (Chest) event.getInventory().getHolder();
LootChest lootChest = MMOCore.plugin.lootChests.getChest(chest.getLocation());
if (lootChest != null)
lootChest.expire(true);
}
@EventHandler(ignoreCancelled = true, priority = EventPriority.HIGH)
public void noBreaking(BlockBreakEvent event) {
Block block = event.getBlock();
if (block.getType() == Material.CHEST) {
LootChest lootChest = MMOCore.plugin.lootChests.getChest(block.getLocation());
if (lootChest != null)
event.setCancelled(true);
}
}
}

View File

@ -52,7 +52,19 @@ public class WaypointsListener implements Listener {
return;
NBTItem nbtItem = NBTItem.get(event.getItem());
if (Objects.equals(nbtItem.getString("MMOCoreItemId"), "WAYPOINT_BOOK"))
InventoryManager.WAYPOINTS.newInventory(PlayerData.get(event.getPlayer())).open();
if (Objects.equals(nbtItem.getString("MMOCoreItemId"), "WAYPOINT_BOOK")) {
String waypointId = nbtItem.getString("WaypointBookId");
Waypoint waypoint = MMOCore.plugin.waypointManager.get(waypointId);
if (waypoint == null)
return;
PlayerData playerData = PlayerData.get(event.getPlayer());
if (playerData.hasWaypoint(waypoint))
return;
playerData.unlockWaypoint(waypoint);
event.getItem().setAmount(event.getItem().getAmount() - 1); // Consume item
MMOCore.plugin.configManager.getSimpleMessage("new-waypoint-book", "waypoint", waypoint.getName()).send(event.getPlayer());
}
}
}

View File

@ -16,7 +16,7 @@ public class RedirectVanillaExp implements Listener {
@EventHandler
public void a(PlayerExpChangeEvent event) {
int a = (int) (event.getAmount() * ratio);
double a = (event.getAmount() * ratio);
if (a > 0)
PlayerData.get(event.getPlayer()).giveExperience(a, EXPSource.VANILLA);
}

View File

@ -4,7 +4,6 @@ import io.lumine.mythic.lib.version.VersionSound;
import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.event.CustomPlayerFishEvent;
import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.api.player.stats.StatType;
import net.Indyuce.mmocore.api.util.MMOCoreUtils;
import net.Indyuce.mmocore.experience.EXPSource;
import net.Indyuce.mmocore.loot.LootBuilder;
@ -80,11 +79,11 @@ public class FishingListener implements Listener {
public FishingData(Player player, FishHook hook, FishingDropTable table) {
this.location = hook.getLocation();
this.caught = table.getRandomItem();
this.caught = table.getRandomItem(PlayerData.get(player));
this.playerData = PlayerData.get(this.player = player);
this.hook = hook;
this.fishStrength = (int) Math.floor(caught.rollTugs() * (1 - PlayerData.get(player).getStats().getStat(StatType.FISHING_STRENGTH) / 100));
this.fishStrength = (int) Math.floor(caught.rollTugs() * (1 - PlayerData.get(player).getStats().getStat("FISHING_STRENGTH") / 100));
this.experienceDropped = caught.rollExperience();
fishing.add(player.getUniqueId());
@ -148,7 +147,7 @@ public class FishingListener implements Listener {
return;
}
if (currentPulls == 0 && RANDOM.nextDouble() < PlayerData.get(player).getStats().getStat(StatType.CRITICAL_FISHING_CHANCE) / 100)
if (currentPulls == 0 && RANDOM.nextDouble() < PlayerData.get(player).getStats().getStat("CRITICAL_FISHING_CHANCE") / 100)
setCriticalFish();
// Check if enough pulls; if not, wait till the next fish event
@ -165,7 +164,7 @@ public class FishingListener implements Listener {
(mainhand != null && mainhand.getType() == Material.FISHING_ROD) ? EquipmentSlot.HAND : EquipmentSlot.OFF_HAND, 1);
// Critical fishing failure
if (!isCriticalFish() && RANDOM.nextDouble() < PlayerData.get(player).getStats().getStat(StatType.CRITICAL_FISHING_FAILURE_CHANCE) / 100) {
if (!isCriticalFish() && RANDOM.nextDouble() < PlayerData.get(player).getStats().getStat("CRITICAL_FISHING_FAILURE_CHANCE") / 100) {
player.setVelocity(hook.getLocation().subtract(player.getLocation()).toVector().setY(0).multiply(3).setY(.5));
hook.getWorld().spawnParticle(Particle.SMOKE_NORMAL, location, 24, 0, 0, 0, .08);
return;

View File

@ -1,7 +1,8 @@
package net.Indyuce.mmocore.listener.profession;
import java.util.Random;
import io.lumine.mythic.lib.MythicLib;
import net.Indyuce.mmocore.api.event.CustomBlockMineEvent;
import net.Indyuce.mmocore.loot.chest.particle.SmallParticleEffect;
import org.bukkit.Location;
import org.bukkit.Particle;
import org.bukkit.entity.Player;
@ -11,10 +12,7 @@ import org.bukkit.inventory.ItemStack;
import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;
import net.Indyuce.mmocore.api.event.CustomBlockMineEvent;
import net.Indyuce.mmocore.api.player.stats.StatType;
import net.Indyuce.mmocore.loot.chest.particle.SmallParticleEffect;
import io.lumine.mythic.lib.MythicLib;
import java.util.Random;
public class PlayerCollectStats implements Listener {
private static final Random random = new Random();
@ -23,26 +21,26 @@ public class PlayerCollectStats implements Listener {
public void a(CustomBlockMineEvent event) {
Player player = event.getPlayer();
// give haste if right enchant
double h = event.getData().getStats().getStat(StatType.GATHERING_HASTE);
// Give haste if right enchant
double h = event.getData().getStats().getStat("GATHERING_HASTE");
if (h > 0 && random.nextDouble() < h * .045) {
new SmallParticleEffect(player, Particle.SPELL_INSTANT);
player.removePotionEffect(PotionEffectType.FAST_DIGGING);
player.addPotionEffect(new PotionEffect(PotionEffectType.FAST_DIGGING, (int) (10 * h), (int) (1 + h / 7)));
}
// drop more items if fortune enchant
double f = event.getData().getStats().getStat(StatType.FORTUNE);
// Drop more items if fortune enchant
double f = event.getData().getStats().getStat("FORTUNE");
if (f > 0 && random.nextDouble() < f * .045) {
int a = (int) (1.5 * Math.sqrt(f / 1.1));
for (ItemStack item : event.getDrops())
item.setAmount(item.getAmount() + a);
}
if(MythicLib.plugin.getVersion().getWrapper().isCropFullyGrown(event.getBlock()))
{
// drop more items if fortune enchant
double l = event.getData().getStats().getStat(StatType.LUCK_OF_THE_FIELD);
if (MythicLib.plugin.getVersion().getWrapper().isCropFullyGrown(event.getBlock())) {
// Drop more CROP items
double l = event.getData().getStats().getStat("LUCK_OF_THE_FIELD");
if (l > 0 && random.nextDouble() < l * .045) {
int a = (int) (1.5 * Math.sqrt(l / 1.1));
Location loc = event.getBlock().getLocation().add(.5, .1, .5);

View File

@ -10,8 +10,7 @@ public class ChestTier {
private final TierEffect effect;
private final ScalingFormula capacity;
private final DropTable table;
public final double chance;
private final double chance;
public ChestTier(ConfigurationSection config) {
effect = config.isConfigurationSection("effect") ? new TierEffect(config.getConfigurationSection("effect")) : null;
@ -24,6 +23,10 @@ public class ChestTier {
return capacity.calculate(player.getLevel());
}
public double getChance() {
return chance;
}
public DropTable getDropTable() {
return table;
}

View File

@ -2,6 +2,7 @@ package net.Indyuce.mmocore.loot.chest;
import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.SoundEvent;
import net.Indyuce.mmocore.util.HashableLocation;
import org.apache.commons.lang.Validate;
import org.bukkit.Location;
import org.bukkit.Material;
@ -9,7 +10,6 @@ import org.bukkit.Particle;
import org.bukkit.block.Block;
import org.bukkit.block.Chest;
import org.bukkit.block.data.BlockData;
import org.bukkit.entity.Player;
import org.bukkit.scheduler.BukkitRunnable;
import javax.annotation.Nullable;
@ -20,7 +20,7 @@ public class LootChest {
private final ReplacedBlock block;
@Nullable
private final BukkitRunnable effectRunnable;
private final long date = System.currentTimeMillis();
private final BukkitRunnable closeRunnable;
private boolean active = true;
@ -36,6 +36,13 @@ public class LootChest {
this.region = region;
this.block = new ReplacedBlock(block);
this.effectRunnable = tier.hasEffect() ? tier.getEffect().startNewRunnable(block.getLocation().add(.5, .5, .5)) : null;
closeRunnable = new BukkitRunnable() {
@Override
public void run() {
expire(false);
}
};
closeRunnable.runTaskLater(MMOCore.plugin, MMOCore.plugin.configManager.lootChestExpireTime);
}
public ChestTier getTier() {
@ -50,15 +57,8 @@ public class LootChest {
return region;
}
public boolean hasPlayerNearby() {
for (Player player : block.loc.getWorld().getPlayers())
if (player.getLocation().distanceSquared(block.loc) < 625)
return true;
return false;
}
public boolean shouldExpire() {
return System.currentTimeMillis() - date > MMOCore.plugin.configManager.lootChestExpireTime;
public boolean isActive() {
return active;
}
/**
@ -76,10 +76,14 @@ public class LootChest {
Validate.isTrue(active, "Chest has already expired");
active = false;
// Close runnable
if (!closeRunnable.isCancelled())
closeRunnable.cancel();
// If a player is responsible of closing the chest, close it with sound
if (player) {
MMOCore.plugin.soundManager.getSound(SoundEvent.CLOSE_LOOT_CHEST).playAt(block.loc);
block.loc.getWorld().spawnParticle(Particle.CRIT, block.loc.clone().add(.5, .5, .5), 16, 0, 0, 0, .5);
MMOCore.plugin.soundManager.getSound(SoundEvent.CLOSE_LOOT_CHEST).playAt(block.loc.bukkit());
block.loc.getWorld().spawnParticle(Particle.CRIT, block.loc.bukkit().add(.5, .5, .5), 16, 0, 0, 0, .5);
}
/*
@ -87,7 +91,7 @@ public class LootChest {
* off and accumulate on the ground (+during dev phase)
*/
else
((Chest) block.loc.getBlock().getState()).getBlockInventory().clear();
((Chest) block.loc.bukkit().getBlock().getState()).getBlockInventory().clear();
block.restore();
if (effectRunnable != null)
@ -97,22 +101,28 @@ public class LootChest {
public static class ReplacedBlock {
private final Material material;
private final BlockData data;
private final Location loc;
private final HashableLocation loc;
public ReplacedBlock(Block block) {
this.material = block.getType();
this.data = block.getBlockData();
this.loc = block.getLocation();
this.loc = new HashableLocation(block.getLocation());
}
public HashableLocation getLocation() {
return loc;
}
@Deprecated
public boolean matches(Location loc) {
return this.loc.getWorld().equals(loc.getWorld()) && this.loc.getBlockX() == loc.getBlockX() && this.loc.getBlockY() == loc.getBlockY()
&& this.loc.getBlockZ() == loc.getBlockZ();
return this.loc.getWorld().equals(loc.getWorld()) && this.loc.getX() == loc.getBlockX() && this.loc.getY() == loc.getBlockY()
&& this.loc.getZ() == loc.getBlockZ();
}
public void restore() {
loc.getBlock().setType(material);
loc.getBlock().setBlockData(data);
Block block = loc.bukkit().getBlock();
block.setType(material);
block.setBlockData(data);
}
}
}

View File

@ -13,6 +13,7 @@ import org.bukkit.block.Chest;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.scheduler.BukkitRunnable;
import org.bukkit.util.Vector;
import org.jetbrains.annotations.NotNull;
import java.util.*;
import java.util.logging.Level;
@ -33,7 +34,7 @@ public class LootChestRegion {
}
};
private static final Random random = new Random();
private static final Random RANDOM = new Random();
public LootChestRegion(ConfigurationSection config) {
Validate.notNull(config, "Could not load config");
@ -85,7 +86,7 @@ public class LootChestRegion {
player.setLastActivity(PlayerActivity.LOOT_CHEST_SPAWN);
// First randomly determine the chest tier
ChestTier tier = rollTier();
ChestTier tier = rollTier(player);
// Find a random location, 20 trials max
Location location = getRandomLocation(player.getPlayer().getLocation());
@ -108,7 +109,7 @@ public class LootChestRegion {
location.getBlock().setType(Material.CHEST);
Chest chest = (Chest) location.getBlock().getState();
tier.getDropTable().collect(builder).forEach(item -> {
Integer slot = slots.get(random.nextInt(slots.size()));
Integer slot = slots.get(RANDOM.nextInt(slots.size()));
chest.getInventory().setItem(slot, item);
slots.remove(slot);
});
@ -116,17 +117,39 @@ public class LootChestRegion {
MMOCore.plugin.lootChests.register(lootChest);
}
// TODO stat to increase chance to get higher tiers?
public ChestTier rollTier() {
/**
* @param player Player rolling the tier
* @return A randomly picked tiers taking into account tier spawn rates
* and the player Chance attribute
*/
@NotNull
public ChestTier rollTier(PlayerData player) {
double chance = player.getStats().getStat("CHANCE") * MMOCore.plugin.configManager.lootChestsChanceWeight;
double s = 0;
double sum = 0;
for (ChestTier tier : tiers)
sum += getTierCoefficient(tier.getChance(), chance);
Validate.isTrue(sum > 0, "No chest tier was found");
double cummulated = 0;
for (ChestTier tier : tiers) {
if (random.nextDouble() < tier.chance / (1 - s))
cummulated += getTierCoefficient(tier.getChance(), chance);
if (RANDOM.nextDouble() < cummulated / sum)
return tier;
s += tier.chance;
}
return tiers.stream().findAny().orElse(null);
throw new RuntimeException("Could not roll chest tier");
}
private static final double CHANCE_COEF = 7 / 100;
/**
* - Chance = 0 | tier coefficient is left unchanged.
* - Chance -> +oo | all tier coefficients are the same (1)
* - Chance = 50 | coefficients become their square roots
*/
private double getTierCoefficient(double initialTierChance, double chance) {
return Math.pow(initialTierChance, 1 / Math.pow(1 + CHANCE_COEF * chance, 1 / 3));
}
public Location getRandomLocation(Location center) {
@ -151,9 +174,9 @@ public class LootChestRegion {
* Chooses a random direction and get the block in
* that direction which has the same height as the player
*/
double a = random.nextDouble() * 2 * Math.PI;
double a = RANDOM.nextDouble() * 2 * Math.PI;
Vector dir = new Vector(Math.cos(a), 0, Math.sin(a))
.multiply(algOptions.minRange + random.nextDouble() * (algOptions.maxRange - algOptions.minRange));
.multiply(algOptions.minRange + RANDOM.nextDouble() * (algOptions.maxRange - algOptions.minRange));
Location random = center.add(dir);
/*

View File

@ -1,4 +1,4 @@
package net.Indyuce.mmocore.loot.droptable.condition;
package net.Indyuce.mmocore.loot.chest.condition;
import java.util.Arrays;
import java.util.List;

View File

@ -1,4 +1,4 @@
package net.Indyuce.mmocore.loot.droptable.condition;
package net.Indyuce.mmocore.loot.chest.condition;
import io.lumine.mythic.lib.api.MMOLineConfig;

View File

@ -1,4 +1,4 @@
package net.Indyuce.mmocore.loot.droptable.condition;
package net.Indyuce.mmocore.loot.chest.condition;
import java.util.List;
import java.util.stream.Stream;

View File

@ -0,0 +1,34 @@
package net.Indyuce.mmocore.loot.chest.condition;
import io.lumine.mythic.lib.api.MMOLineConfig;
import org.apache.commons.lang.Validate;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.entity.Entity;
public class DistanceCondition extends Condition{
private final Location location;
private final double distance;
public DistanceCondition(MMOLineConfig config) {
super(config);
Validate.isTrue(config.contains("world"));
Validate.isTrue(config.contains("x"));
Validate.isTrue(config.contains("y"));
Validate.isTrue(config.contains("z"));
Validate.isTrue(config.contains("distance"));
Validate.isTrue(Bukkit.getWorld(config.getString("world"))!=null,"This world doesn't exist");
location=new Location(Bukkit.getWorld(config.getString("world")),config.getDouble("x"),
config.getDouble("y"),config.getDouble("z"));
distance=config.getDouble("distance");
}
@Override
public boolean isMet(ConditionInstance entity) {
Entity entity1=entity.getEntity();
return entity1.getWorld().equals(location.getWorld())&&location.distance(entity1.getLocation())<distance;
}
}

View File

@ -1,4 +1,4 @@
package net.Indyuce.mmocore.loot.droptable.condition;
package net.Indyuce.mmocore.loot.chest.condition;
import net.Indyuce.mmocore.api.player.PlayerData;
import io.lumine.mythic.lib.api.MMOLineConfig;

View File

@ -1,4 +1,4 @@
package net.Indyuce.mmocore.loot.droptable.condition;
package net.Indyuce.mmocore.loot.chest.condition;
import io.lumine.mythic.lib.api.MMOLineConfig;
import org.bukkit.entity.Player;
@ -15,8 +15,6 @@ public class PermissionCondition extends Condition {
@Override
public boolean isMet(ConditionInstance entity) {
if (entity.getEntity() instanceof Player)
return entity.getEntity().hasPermission(perm);
return false;
return entity.getEntity() instanceof Player && entity.getEntity().hasPermission(perm);
}
}

View File

@ -1,4 +1,4 @@
package net.Indyuce.mmocore.loot.droptable.condition;
package net.Indyuce.mmocore.loot.chest.condition;
import java.util.Arrays;
import java.util.List;

View File

@ -5,8 +5,8 @@ import java.util.List;
import java.util.Set;
import java.util.logging.Level;
import net.Indyuce.mmocore.loot.droptable.condition.Condition;
import net.Indyuce.mmocore.loot.droptable.condition.ConditionInstance;
import net.Indyuce.mmocore.loot.chest.condition.Condition;
import net.Indyuce.mmocore.loot.chest.condition.ConditionInstance;
import net.Indyuce.mmocore.loot.droptable.dropitem.DropItem;
import org.apache.commons.lang.Validate;
import org.bukkit.configuration.ConfigurationSection;
@ -73,7 +73,7 @@ public class DropTable extends PostLoadObject {
public List<ItemStack> collect(LootBuilder builder) {
for (DropItem item : drops)
if (item.rollChance() && builder.getCapacity() >= item.getWeight()) {
if (item.rollChance(builder.getEntity()) && builder.getCapacity() >= item.getWeight()) {
item.collect(builder);
builder.reduceCapacity(item.getWeight());
}

View File

@ -2,41 +2,45 @@ package net.Indyuce.mmocore.loot.droptable.dropitem;
import java.util.Random;
import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.loot.LootBuilder;
import net.Indyuce.mmocore.api.util.math.formula.RandomAmount;
import io.lumine.mythic.lib.api.MMOLineConfig;
public abstract class DropItem {
protected static final Random random = new Random();
protected static final Random random = new Random();
private final double chance, weight;
private final RandomAmount amount;
private final double chance, weight;
private final RandomAmount amount;
public DropItem(MMOLineConfig config) {
chance = config.args().length > 0 ? Double.parseDouble(config.args()[0]) : 1;
amount = config.args().length > 1 ? new RandomAmount(config.args()[1]) : new RandomAmount(1, 1);
weight = config.args().length > 2 ? Double.parseDouble(config.args()[2]) : 0;
}
public DropItem(MMOLineConfig config) {
chance = config.args().length > 0 ? Double.parseDouble(config.args()[0]) : 1;
amount = config.args().length > 1 ? new RandomAmount(config.args()[1]) : new RandomAmount(1, 1);
weight = config.args().length > 2 ? Double.parseDouble(config.args()[2]) : 0;
}
public RandomAmount getAmount() {
return amount;
}
public RandomAmount getAmount() {
return amount;
}
public double getChance() {
return chance;
}
public double getChance() {
return chance;
}
public double getWeight() {
return weight;
}
public double getWeight() {
return weight;
}
public int rollAmount() {
return amount.calculateInt();
}
public int rollAmount() {
return amount.calculateInt();
}
public boolean rollChance() {
return random.nextDouble() < chance;
}
/**
* If the player chance is 0 the random value will remain the same. When he get lucks the chance gets closer to one.
*/
public boolean rollChance(PlayerData player) {
return Math.pow(random.nextDouble(), 1 / Math.log(1 + player.getStats().getStat("CHANCE"))) < chance;
}
public abstract void collect(LootBuilder builder);
public abstract void collect(LootBuilder builder);
}

View File

@ -3,7 +3,7 @@ package net.Indyuce.mmocore.loot.droptable.dropitem;
import io.lumine.mythic.lib.api.MMOLineConfig;
import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.loot.droptable.DropTable;
import net.Indyuce.mmocore.loot.droptable.condition.ConditionInstance;
import net.Indyuce.mmocore.loot.chest.condition.ConditionInstance;
import net.Indyuce.mmocore.loot.LootBuilder;
import net.Indyuce.mmocore.api.player.PlayerData;
import org.apache.commons.lang.Validate;

View File

@ -27,6 +27,7 @@ public class ConfigManager {
public String partyChatPrefix, noSkillBoundPlaceholder;
public ChatColor staminaFull, staminaHalf, staminaEmpty;
public long combatLogTimer, lootChestExpireTime, lootChestPlayerCooldown, globalSkillCooldown;
public double lootChestsChanceWeight;
private final FileConfiguration messages;
private final boolean chatInput;
@ -93,10 +94,11 @@ public class ConfigManager {
chatInput = MMOCore.plugin.getConfig().getBoolean("use-chat-input");
partyChatPrefix = MMOCore.plugin.getConfig().getString("party.chat-prefix");
combatLogTimer = MMOCore.plugin.getConfig().getInt("combat-log.timer") * 1000L;
lootChestExpireTime = Math.max(MMOCore.plugin.getConfig().getInt("loot-chests.chest-expire-time"), 1) * 1000L;
lootChestExpireTime = Math.max(MMOCore.plugin.getConfig().getInt("loot-chests.chest-expire-time"), 1) * 20;
lootChestPlayerCooldown = (long) MMOCore.plugin.getConfig().getDouble("player-cooldown") * 1000L;
globalSkillCooldown = MMOCore.plugin.getConfig().getLong("global-skill-cooldown") * 50;
noSkillBoundPlaceholder = getSimpleMessage("no-skill-placeholder").message();
lootChestsChanceWeight = MMOCore.plugin.getConfig().getDouble("chance-stat-weight.loot-chests");
staminaFull = getColorOrDefault("stamina-whole", ChatColor.GREEN);
staminaHalf = getColorOrDefault("stamina-half", ChatColor.DARK_GREEN);

View File

@ -1,33 +1,36 @@
package net.Indyuce.mmocore.manager;
import java.util.*;
import java.util.logging.Level;
import org.bukkit.Location;
import org.bukkit.configuration.file.FileConfiguration;
import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.ConfigFile;
import net.Indyuce.mmocore.loot.chest.LootChest;
import net.Indyuce.mmocore.loot.chest.LootChestRegion;
import net.Indyuce.mmocore.util.HashableLocation;
import org.bukkit.Location;
import org.bukkit.configuration.file.FileConfiguration;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.logging.Level;
public class LootChestManager implements MMOCoreManager {
/**
* Active loot chests in the server
*/
private final Set<LootChest> active = new HashSet<>();
/**
* Active loot chests in the server
*/
private final Map<HashableLocation, LootChest> active = new HashMap<>();
/**
* Registered loot chest regions
*/
private final Map<String, LootChestRegion> regions = new HashMap<>();
/**
* Registered loot chest regions
*/
private final Map<String, LootChestRegion> regions = new HashMap<>();
public boolean hasRegion(String id) {
return regions.containsKey(id);
}
public boolean hasRegion(String id) {
return regions.containsKey(id);
}
/**
* @return Region with specific identifier
@ -38,48 +41,42 @@ public class LootChestManager implements MMOCoreManager {
return Objects.requireNonNull(regions.get(id), "Could not find region with ID '" + id + "'");
}
public Collection<LootChestRegion> getRegions() {
return regions.values();
}
public Collection<LootChestRegion> getRegions() {
return regions.values();
}
public Set<LootChest> getActive() {
return active;
}
public Collection<LootChest> getActive() {
return active.values();
}
public void register(LootChest chest) {
active.add(chest);
}
public void register(LootChest chest) {
active.put(chest.getBlock().getLocation(), chest);
}
public void unregister(LootChest chest) {
active.remove(chest);
}
public void unregister(LootChest chest) {
active.remove(chest.getBlock().getLocation());
}
@Nullable
public LootChest getChest(Location loc) {
@Nullable
public LootChest getChest(Location loc) {
return active.get(new HashableLocation(loc));
}
for (LootChest chest : active)
if (chest.getBlock().matches(loc))
return chest;
@Override
public void initialize(boolean clearBefore) {
if (clearBefore) {
regions.values().forEach(region -> region.getRunnable().cancel());
regions.clear();
}
return null;
}
@Override
public void initialize(boolean clearBefore) {
if (clearBefore) {
regions.values().forEach(region -> region.getRunnable().cancel());
regions.clear();
}
FileConfiguration config = new ConfigFile("loot-chests").getConfig();
for (String key : config.getKeys(false))
try {
LootChestRegion region = new LootChestRegion(config.getConfigurationSection(key));
regions.put(region.getId(), region);
} catch (IllegalArgumentException exception) {
MMOCore.plugin.getLogger().log(Level.WARNING,
"An error occured while trying to load loot chest region '" + key + "': " + exception.getMessage());
}
}
FileConfiguration config = new ConfigFile("loot-chests").getConfig();
for (String key : config.getKeys(false))
try {
LootChestRegion region = new LootChestRegion(config.getConfigurationSection(key));
regions.put(region.getId(), region);
} catch (IllegalArgumentException exception) {
MMOCore.plugin.getLogger().log(Level.WARNING,
"An error occured while trying to load loot chest region '" + key + "': " + exception.getMessage());
}
}
}

View File

@ -11,7 +11,7 @@ import org.bukkit.configuration.ConfigurationSection;
import com.google.gson.JsonParseException;
import net.Indyuce.mmocore.api.block.BlockType;
import net.Indyuce.mmocore.loot.droptable.condition.Condition;
import net.Indyuce.mmocore.loot.chest.condition.Condition;
import net.Indyuce.mmocore.loot.droptable.dropitem.DropItem;
import net.Indyuce.mmocore.experience.source.type.ExperienceSource;
import net.Indyuce.mmocore.api.load.DefaultMMOLoader;

View File

@ -0,0 +1,71 @@
package net.Indyuce.mmocore.manager;
import io.lumine.mythic.lib.MythicLib;
import net.Indyuce.mmocore.api.ConfigFile;
import net.Indyuce.mmocore.player.stats.StatInfo;
import net.Indyuce.mmocore.api.util.math.formula.LinearValue;
import net.Indyuce.mmocore.experience.Profession;
import org.bukkit.configuration.file.FileConfiguration;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.text.DecimalFormat;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
public class StatManager implements MMOCoreManager {
private final Map<String, StatInfo> loaded = new HashMap<>();
@Override
public void initialize(boolean clearBefore) {
if (clearBefore)
loaded.clear();
FileConfiguration config = new ConfigFile("stats").getConfig();
// Read decimal formats
for (String key : config.getConfigurationSection("decimal-format").getKeys(false))
registerDecimalFormat(key, MythicLib.plugin.getMMOConfig().newDecimalFormat(config.getString("decimal-format." + key)));
// Read default formulas
for (String key : config.getConfigurationSection("default").getKeys(false))
registerDefaultFormula(key, new LinearValue(config.getConfigurationSection("default." + key)));
}
public Collection<StatInfo> getLoaded() {
return loaded.values();
}
@Nullable
public StatInfo getInfo(String stat) {
return loaded.get(stat);
}
public void registerProfession(String stat, Profession profession) {
compute(stat).profession = profession;
}
public void registerDefaultFormula(String stat, LinearValue defaultFormula) {
compute(stat).defaultInfo = defaultFormula;
}
public void registerDecimalFormat(String stat, DecimalFormat format) {
compute(stat).format = format;
}
/**
* @return A stat info for the specified stat. If it doesn't
* exist when method is called, it is registered into the map
*/
@NotNull
private StatInfo compute(String stat) {
StatInfo found = loaded.get(stat);
if (found != null)
return found;
StatInfo newInfo = new StatInfo(stat);
loaded.put(stat, newInfo);
return newInfo;
}
}

View File

@ -25,6 +25,7 @@ public class WaypointManager implements MMOCoreManager {
return waypoints.containsKey(id);
}
@Nullable
public Waypoint get(String id) {
return waypoints.get(id);
}
@ -55,5 +56,12 @@ public class WaypointManager implements MMOCoreManager {
} catch (RuntimeException exception) {
MMOCore.log(Level.WARNING, "Could not load waypoint '" + key + "': " + exception.getMessage());
}
for (Waypoint waypoint : waypoints.values())
try {
waypoint.postLoad();
} catch (RuntimeException exception) {
MMOCore.log(Level.WARNING, "Could not post-load waypoint '" + waypoint.getId() + "': " + exception.getMessage());
}
}
}

View File

@ -9,7 +9,6 @@ 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.player.stats.StatType;
import net.Indyuce.mmocore.guild.provided.Guild;
import net.Indyuce.mmocore.manager.data.PlayerDataManager;
import net.Indyuce.mmocore.manager.data.mysql.MySQLTableEditor.Table;
@ -35,6 +34,13 @@ public class MySQLPlayerDataManager extends PlayerDataManager {
try {
MMOCore.sqlDebug("Loading data for: '" + data.getUniqueId() + "'...");
// Initialize custom resources
if (!data.hasUsedTemporaryData()) {
data.setMana(data.getStats().getStat("MAX_MANA"));
data.setStamina(data.getStats().getStat("MAX_STAMINA"));
data.setStellium(data.getStats().getStat("MAX_STELLIUM"));
}
if (!result.next()) {
data.setLevel(getDefaultData().getLevel());
data.setClassPoints(getDefaultData().getClassPoints());
@ -44,12 +50,6 @@ public class MySQLPlayerDataManager extends PlayerDataManager {
data.setExperience(0);
data.getQuestData().updateBossBar();
if (!data.hasUsedTemporaryData()) {
data.setMana(data.getStats().getStat(StatType.MAX_MANA));
data.setStamina(data.getStats().getStat(StatType.MAX_STAMINA));
data.setStellium(data.getStats().getStat(StatType.MAX_STELLIUM));
}
data.setFullyLoaded();
MMOCore.sqlDebug("Loaded DEFAULT data for: '" + data.getUniqueId() + "' as no saved data was found.");
return;
@ -69,12 +69,6 @@ public class MySQLPlayerDataManager extends PlayerDataManager {
json.entrySet().forEach(entry -> data.getItemClaims().put(entry.getKey(), entry.getValue().getAsInt()));
}
if (!data.hasUsedTemporaryData()) {
data.setMana(data.getStats().getStat(StatType.MAX_MANA));
data.setStamina(data.getStats().getStat(StatType.MAX_STAMINA));
data.setStellium(data.getStats().getStat(StatType.MAX_STELLIUM));
}
if (!isEmpty(result.getString("guild"))) {
Guild guild = provider.getGuildManager().getGuild(result.getString("guild"));
data.setGuild(guild.getMembers().has(data.getUniqueId()) ? guild : null);

View File

@ -6,7 +6,6 @@ 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.player.stats.StatType;
import net.Indyuce.mmocore.guild.provided.Guild;
import net.Indyuce.mmocore.manager.data.DataProvider;
import net.Indyuce.mmocore.manager.data.PlayerDataManager;
@ -41,9 +40,9 @@ public class YAMLPlayerDataManager extends PlayerDataManager {
data.setClass(MMOCore.plugin.classManager.get(config.getString("class")));
if (!data.hasUsedTemporaryData()) {
data.setMana(data.getStats().getStat(StatType.MAX_MANA));
data.setStamina(data.getStats().getStat(StatType.MAX_STAMINA));
data.setStellium(data.getStats().getStat(StatType.MAX_STELLIUM));
data.setMana(data.getStats().getStat("MAX_MANA"));
data.setStamina(data.getStats().getStat("MAX_STAMINA"));
data.setStellium(data.getStats().getStat("MAX_STELLIUM"));
}
if (config.contains("guild")) {

View File

@ -7,11 +7,10 @@ import net.Indyuce.mmocore.api.block.BlockInfo.RegeneratingBlock;
import net.Indyuce.mmocore.api.block.BlockType;
import net.Indyuce.mmocore.api.block.SkullBlockType;
import net.Indyuce.mmocore.api.block.VanillaBlockType;
import net.Indyuce.mmocore.loot.droptable.condition.Condition;
import net.Indyuce.mmocore.loot.droptable.condition.ConditionInstance;
import net.Indyuce.mmocore.loot.chest.condition.Condition;
import net.Indyuce.mmocore.loot.chest.condition.ConditionInstance;
import net.Indyuce.mmocore.api.util.MMOCoreUtils;
import io.lumine.mythic.lib.api.MMOLineConfig;
import net.Indyuce.mmocore.manager.profession.SpecificProfessionManager;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.block.Block;

View File

@ -4,17 +4,19 @@ import io.lumine.mythic.lib.MythicLib;
import net.Indyuce.mmocore.MMOCore;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.enchantments.Enchantment;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
public class EnchantManager extends SpecificProfessionManager {
private final Map<Enchantment, Double> base = new HashMap<>();
private final Map<Enchantment, Double> base = new HashMap<>();
public EnchantManager() {
super("base-enchant-exp");
}
public EnchantManager() {
super("base-enchant-exp");
}
@Override
public void loadProfessionConfiguration(ConfigurationSection config) {
@ -27,17 +29,20 @@ public class EnchantManager extends SpecificProfessionManager {
}
}
public void registerBaseExperience(Enchantment enchant, double value) {
base.put(enchant, value);
}
public void registerBaseExperience(Enchantment enchant, double value) {
base.put(enchant, value);
}
public double getBaseExperience(Enchantment enchant) {
return base.get(enchant);
}
@NotNull
public double getBaseExperience(Enchantment enchant) {
// Can be null if argument passed is an enchant with no config attached to it
@Nullable Double found = base.get(enchant);
return found == null ? 0 : found;
}
@Override
public void initialize(boolean clearBefore) {
if (clearBefore)
base.clear();
}
@Override
public void initialize(boolean clearBefore) {
if (clearBefore)
base.clear();
}
}

View File

@ -2,8 +2,9 @@ package net.Indyuce.mmocore.manager.profession;
import io.lumine.mythic.lib.api.MMOLineConfig;
import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.loot.droptable.condition.Condition;
import net.Indyuce.mmocore.loot.droptable.condition.ConditionInstance;
import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.loot.chest.condition.Condition;
import net.Indyuce.mmocore.loot.chest.condition.ConditionInstance;
import net.Indyuce.mmocore.loot.droptable.dropitem.fishing.FishingDropItem;
import org.apache.commons.lang.Validate;
import org.bukkit.configuration.ConfigurationSection;
@ -29,6 +30,11 @@ public class FishingManager extends SpecificProfessionManager {
} catch (IllegalArgumentException exception) {
MMOCore.log(Level.WARNING, "Could not load fishing drop table " + key + ": " + exception.getMessage());
}
// Link fishing stats to this profession
MMOCore.plugin.statManager.registerProfession("FISHING_STRENGTH", getLinkedProfession());
MMOCore.plugin.statManager.registerProfession("CRITICAL_FISHING_CHANCE", getLinkedProfession());
MMOCore.plugin.statManager.registerProfession("CRITICAL_FISHING_FAILURE_CHANCE", getLinkedProfession());
}
public FishingDropTable calculateDropTable(Entity entity) {
@ -44,7 +50,6 @@ public class FishingManager extends SpecificProfessionManager {
public static class FishingDropTable {
private final Set<Condition> conditions = new HashSet<>();
private final List<FishingDropItem> items = new ArrayList<>();
private double maxWeight = 0;
public FishingDropTable(ConfigurationSection section) {
Validate.notNull(section, "Could not load config");
@ -70,7 +75,6 @@ public class FishingManager extends SpecificProfessionManager {
try {
FishingDropItem dropItem = new FishingDropItem(new MMOLineConfig(str));
items.add(dropItem);
maxWeight += dropItem.getItem().getWeight();
} catch (RuntimeException exception) {
MMOCore.plugin.getLogger().log(Level.WARNING,
"Could not load item '" + str + "' from fishing drop table '" + id + "': " + exception.getMessage());
@ -90,12 +94,25 @@ public class FishingManager extends SpecificProfessionManager {
return conditions;
}
public FishingDropItem getRandomItem() {
double randomCoefficient = RANDOM.nextDouble() * maxWeight;
/**
* The chance stat will make low weight items more
* likely to be chosen by the algorithm
*
* @return Randomly computed fishing drop item
*/
public FishingDropItem getRandomItem(PlayerData player) {
double chance = player.getStats().getStat("CHANCE");
for (FishingDropItem item : items)
if ((randomCoefficient -= item.getItem().getWeight()) <= 0)
//chance=0 ->the tier.chance remains the same
//chance ->+inf -> the tier.chance becomes the same for everyone, uniform law
//chance=8-> tierChance=sqrt(tierChance)
double sum = 0;
double randomCoefficient=RANDOM.nextDouble();
for (FishingDropItem item : items) {
sum += Math.pow(item.getItem().getWeight(), 1 / Math.log(1 + chance));
if(sum<randomCoefficient)
return item;
}
throw new NullPointerException("Could not find item in drop table");
}

View File

@ -58,8 +58,8 @@ public class BoosterManager {
return d;
}
public int calculateExp(Profession profession, double exp) {
return (int) (exp * getMultiplier(profession));
public double calculateExp(Profession profession, double exp) {
return (exp * getMultiplier(profession));
}
/**

View File

@ -1,8 +1,8 @@
package net.Indyuce.mmocore.manager.social;
import io.lumine.mythic.lib.UtilityMethods;
import io.lumine.mythic.lib.api.stat.modifier.StatModifier;
import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.player.stats.StatType;
import net.Indyuce.mmocore.manager.MMOCoreManager;
import org.bukkit.configuration.ConfigurationSection;
@ -26,8 +26,7 @@ public class PartyManager implements MMOCoreManager {
if (config != null)
for (String key : config.getKeys(false))
try {
StatType stat = StatType.valueOf(key.toUpperCase().replace("-", "_").replace(" ", "_"));
buffs.add(new StatModifier("mmocoreParty", stat.name(), config.getString(key)));
buffs.add(new StatModifier("mmocoreParty", UtilityMethods.enumName(key), config.getString(key)));
} catch (IllegalArgumentException exception) {
MMOCore.log(Level.WARNING, "Could not load party buff '" + key + "': " + exception.getMessage());
}

View File

@ -0,0 +1,21 @@
package net.Indyuce.mmocore.party;
import io.lumine.mythic.lib.comp.target.InteractionType;
import io.lumine.mythic.lib.comp.target.TargetRestriction;
import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.player.PlayerData;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
public class MMOCoreTargetRestriction implements TargetRestriction {
@Override
public boolean canTarget(Player player, LivingEntity livingEntity, InteractionType interactionType) {
if (!interactionType.isOffense() || !(livingEntity instanceof Player) || livingEntity.hasMetadata("NPC"))
return true;
AbstractParty party = MMOCore.plugin.partyModule.getParty(PlayerData.get(player));
// TODO check for guild
return party == null || !party.hasMember((Player) livingEntity);
}
}

View File

@ -1,13 +1,16 @@
package net.Indyuce.mmocore.party;
import net.Indyuce.mmocore.party.compat.*;
import net.Indyuce.mmocore.party.compat.DungeonsXLPartyModule;
import net.Indyuce.mmocore.party.compat.McMMOPartyModule;
import net.Indyuce.mmocore.party.compat.PAFPartyModule;
import net.Indyuce.mmocore.party.compat.PartiesPartyModule;
import net.Indyuce.mmocore.party.provided.MMOCorePartyModule;
import org.bukkit.Bukkit;
import javax.inject.Provider;
public enum PartyModuleType {
DUNGEONS("Dungeons", DungeonsPartyModule::new),
// DUNGEONS("Dungeons", DungeonsPartyModule::new),
DUNGEONSXL("DungeonsXL", DungeonsXLPartyModule::new),
MCMMO("mcMMO", McMMOPartyModule::new),
MMOCORE("MMOCore", MMOCorePartyModule::new),

View File

@ -2,7 +2,6 @@ package net.Indyuce.mmocore.party.provided;
import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.listener.PartyListener;
import net.Indyuce.mmocore.party.PartyModule;
import org.apache.commons.lang.Validate;
import org.bukkit.Bukkit;

View File

@ -1,16 +1,10 @@
package net.Indyuce.mmocore.listener;
package net.Indyuce.mmocore.party.provided;
import io.lumine.mythic.lib.api.event.PlayerAttackEvent;
import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.event.social.PartyChatEvent;
import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.manager.ConfigManager.SimpleMessage;
import net.Indyuce.mmocore.party.AbstractParty;
import net.Indyuce.mmocore.party.provided.MMOCorePartyModule;
import net.Indyuce.mmocore.party.provided.Party;
import org.bukkit.Bukkit;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
@ -45,21 +39,4 @@ public class PartyListener implements Listener {
party.getOnlineMembers().forEach(member -> format.send(member.getPlayer()));
});
}
/**
* Cancel damage of players from the same party
*
* @deprecated This should be useful with the {@link io.lumine.mythic.lib.comp.target.TargetRestriction} update
*/
@Deprecated
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
public void b(PlayerAttackEvent event) {
LivingEntity entity = event.getEntity();
if (entity instanceof Player && !entity.hasMetadata("NPC")) {
PlayerData targetData = PlayerData.get((Player) event.getEntity());
AbstractParty party = targetData.getParty();
if (party != null && party.hasMember(event.getData().getPlayer()))
event.setCancelled(true);
}
}
}

View File

@ -3,8 +3,8 @@ package net.Indyuce.mmocore.player;
import net.Indyuce.mmocore.api.player.PlayerData;
/**
* Some item that can be unlocked. ALl unlockable are saved in the same list in
* the player data. This useful list can be used for:
* Some item that can be unlocked. All unlockables are saved in the
* same list in the player data. This useful list can be used for:
* - waypoints
* - skill tree nodes
* - skills using skill books? TODO
@ -15,8 +15,8 @@ import net.Indyuce.mmocore.api.player.PlayerData;
public interface Unlockable {
/**
* Format being used is the minecraft's default
* namespaced key format, e.g "skill_tree:strength_1_5"
* Format being used is the minecraft's default namespaced
* key format, e.g "skill_tree:strength_1_5" for readability
*/
String getUnlockNamespacedKey();
}

View File

@ -0,0 +1,71 @@
package net.Indyuce.mmocore.player.stats;
import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.util.math.formula.LinearValue;
import net.Indyuce.mmocore.experience.Profession;
import org.jetbrains.annotations.NotNull;
import java.text.DecimalFormat;
import java.util.Objects;
/**
* @author Jules
* @impl MMOCore used to have a giant enum of all the stat types
* which is now incompatible with MythicLib because the MMO plugins
* now have completely OPEN to edition numeric stat registries
*/
public class StatInfo {
public final String name;
/**
* Profession linked to that stat. Stats which have a profession linked to
* them do NOT scale on the main player level but rather on that specific
* profession level
*/
public Profession profession;
/**
* Default formula for the stat
*/
public LinearValue defaultInfo;
/**
* How that stat displays anywhere in GUIs
*/
public DecimalFormat format;
private static final DecimalFormat DEFAULT_DECIMAL_FORMAT = new DecimalFormat("0.#");
public StatInfo(String name) {
this.name = name;
}
@NotNull
public String format(double d) {
return (format == null ? DEFAULT_DECIMAL_FORMAT : format).format(d);
}
@NotNull
public LinearValue getDefaultFormula() {
return defaultInfo == null ? LinearValue.ZERO : defaultInfo;
}
@NotNull
public static StatInfo valueOf(String str) {
StatInfo found = MMOCore.plugin.statManager.getInfo(str);
return found == null ? new StatInfo(str) : found;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
StatInfo statInfo = (StatInfo) o;
return name.equals(statInfo.name);
}
@Override
public int hashCode() {
return Objects.hash(name);
}
}

View File

@ -3,4 +3,6 @@ package net.Indyuce.mmocore.quest;
public interface AbstractQuest {
public String getName();
public String getId();
}

View File

@ -0,0 +1,40 @@
package net.Indyuce.mmocore.quest;
import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.quest.Quest;
import net.Indyuce.mmocore.quest.compat.QuestModule;
import org.bukkit.entity.Player;
public class MMOCoreQuestModule implements QuestModule {
@Override
public AbstractQuest getQuestOrThrow(String id) {
Quest quest=MMOCore.plugin.questManager.get(id);
if(quest==null)
return null;
return new MMOCoreQuest(quest);
}
@Override
public boolean hasCompletedQuest(String quest, Player player) {
return false;
}
public class MMOCoreQuest implements AbstractQuest {
Quest quest;
public MMOCoreQuest(Quest quest) {
this.quest = quest;
}
@Override
public String getName() {
return null;
}
@Override
public String getId() {
return null;
}
}
}

View File

@ -1,16 +0,0 @@
package net.Indyuce.mmocore.quest;
import net.Indyuce.mmocore.api.player.PlayerData;
public interface QuestModule<T extends AbstractQuest, U extends PlayerQuestData<T>> {
/**
* @return Quest with given name
*/
public T getQuestOrThrow(String id);
/**
* @return Info about the completed quests from a specific player
*/
public U getQuestData(PlayerData playerData);
}

View File

@ -0,0 +1,32 @@
package net.Indyuce.mmocore.quest;
import net.Indyuce.mmocore.quest.compat.BeautyQuestsModule;
import net.Indyuce.mmocore.quest.compat.BlackVeinQuestsModule;
import net.Indyuce.mmocore.quest.compat.QuestCreatorModule;
import net.Indyuce.mmocore.quest.compat.QuestModule;
import org.bukkit.Bukkit;
import javax.inject.Provider;
public enum QuestModuleType {
MMOCORE("MMOCore", MMOCoreQuestModule::new),
QUESTS("Quests", BlackVeinQuestsModule::new),
BEAUTY_QUEST("BeautyQuests", BeautyQuestsModule::new),
QUEST_CREATOR("QuestCreator", QuestCreatorModule::new);
private final String pluginName;
private final Provider<QuestModule> provider;
QuestModuleType(String pluginName, Provider<QuestModule> provider) {
this.pluginName = pluginName;
this.provider = provider;
}
public boolean isValid() {
return Bukkit.getPluginManager().getPlugin(pluginName) != null;
}
public QuestModule provideModule() {
return provider.get();
}
}

View File

@ -0,0 +1,44 @@
package net.Indyuce.mmocore.quest.compat;
import fr.skytasul.quests.api.QuestsAPI;
import fr.skytasul.quests.players.PlayerAccount;
import fr.skytasul.quests.players.PlayerQuestDatas;
import fr.skytasul.quests.players.PlayersManager;
import fr.skytasul.quests.structure.Quest;
import net.Indyuce.mmocore.quest.AbstractQuest;
import org.bukkit.entity.Player;
public class BeautyQuestsModule implements QuestModule<BeautyQuestsModule.BeautyQuestQuest> {
@Override
public BeautyQuestQuest getQuestOrThrow(String questId) {
Quest quest = QuestsAPI.getQuests().getQuest(Integer.parseInt(questId));
return quest == null ? null : new BeautyQuestQuest(quest);
}
@Override
public boolean hasCompletedQuest(String questId, Player player) {
PlayerAccount account = PlayersManager.getPlayerAccount(player);
PlayerQuestDatas quest = account.getQuestDatas(QuestsAPI.getQuests().getQuest(Integer.parseInt(questId)));
return quest.isFinished();
}
public class BeautyQuestQuest implements AbstractQuest {
Quest quest;
public BeautyQuestQuest(Quest quest) {
this.quest = quest;
}
@Override
public String getName() {
return quest.getName();
}
@Override
public String getId() {
return String.valueOf(quest.getID());
}
}
}

View File

@ -0,0 +1,47 @@
package net.Indyuce.mmocore.quest.compat;
import me.blackvein.quests.Quest;
import me.blackvein.quests.Quester;
import me.blackvein.quests.Quests;
import net.Indyuce.mmocore.quest.AbstractQuest;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
public class BlackVeinQuestsModule implements QuestModule<BlackVeinQuestsModule.BlackVeinQuestQuest> {
private final Quests plugin = (Quests) Bukkit.getPluginManager().getPlugin("Quests");
@Override
public BlackVeinQuestQuest getQuestOrThrow(String id) {
Quests plugin = (Quests) Bukkit.getPluginManager().getPlugin("Quests");
return plugin.getQuestById(id) == null ? null : new BlackVeinQuestQuest(plugin.getQuestById(id));
}
@Override
public boolean hasCompletedQuest(String questId, Player player) {
Quester quester = plugin.getQuester(player.getUniqueId());
for (Quest quest : quester.getCompletedQuests())
if (quest.getId().equals(questId))
return true;
return false;
}
public class BlackVeinQuestQuest implements AbstractQuest {
private final Quest quest;
public BlackVeinQuestQuest(Quest quest) {
this.quest = quest;
}
@Override
public String getName() {
return quest.getName();
}
@Override
public String getId() {
return quest.getId();
}
}
}

View File

@ -0,0 +1,57 @@
package net.Indyuce.mmocore.quest.compat;
import com.guillaumevdn.questcreator.ConfigQC;
import com.guillaumevdn.questcreator.data.user.QuestHistoryElement;
import com.guillaumevdn.questcreator.data.user.UserQC;
import com.guillaumevdn.questcreator.lib.model.ElementModel;
import com.guillaumevdn.questcreator.lib.quest.QuestEndType;
import net.Indyuce.mmocore.quest.AbstractQuest;
import org.apache.commons.lang.Validate;
import org.bukkit.entity.Player;
import java.util.Arrays;
import java.util.List;
public class QuestCreatorModule implements QuestModule<QuestCreatorModule.QuestCreatorQuest> {
@Override
public QuestCreatorQuest getQuestOrThrow(String id) {
return new QuestCreatorQuest(id);
}
@Override
public boolean hasCompletedQuest(String questId, Player player) {
UserQC playerData = UserQC.cachedOrNull(player);
Validate.notNull(playerData, "QuestCreator User hasn't been loaded!");
// Gets all the quests the player has succeeded at
List<QuestHistoryElement> elements = playerData.getQuestHistory().getElements(questId, Arrays.asList(QuestEndType.SUCCESS), 0);
for (QuestHistoryElement el : elements)
if (el.getModelId().equals(questId))
return true;
return false;
}
/**
* QC ElementModel corresponds to our quest and their
* quests correspond to our Quest progress class
*/
public class QuestCreatorQuest implements AbstractQuest {
ElementModel questModel;
public QuestCreatorQuest(String modelId) {
questModel = ConfigQC.models.getElement(modelId).orNull();
}
@Override
public String getName() {
return questModel.getDisplayName().getId();
}
@Override
public String getId() {
return questModel.getId();
}
}
}

View File

@ -0,0 +1,17 @@
package net.Indyuce.mmocore.quest.compat;
import net.Indyuce.mmocore.quest.AbstractQuest;
import org.bukkit.entity.Player;
public interface QuestModule<T extends AbstractQuest> {
/**
* @return Quest with given identifier
*/
public T getQuestOrThrow(String id);
/**
* @return If a specific player has made a certain quest
*/
public boolean hasCompletedQuest(String quest, Player player);
}

View File

@ -4,6 +4,7 @@ import io.lumine.mythic.lib.api.player.EquipmentSlot;
import io.lumine.mythic.lib.player.cooldown.CooldownObject;
import io.lumine.mythic.lib.player.modifier.ModifierSource;
import io.lumine.mythic.lib.player.skill.PassiveSkill;
import io.lumine.mythic.lib.skill.custom.condition.Condition;
import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.api.util.math.formula.IntegerLinearValue;
import net.Indyuce.mmocore.api.util.math.formula.LinearValue;
@ -17,6 +18,9 @@ public class ClassSkill implements CooldownObject {
private final int unlockLevel, maxSkillLevel;
private final Map<String, LinearValue> modifiers = new HashMap<>();
@Deprecated
private final Set<Condition> unlockConditions = new HashSet<>();
/**
* Class used to save information about skills IN A CLASS CONTEXT i.e at
* which level the skill can be unlocked, etc.

Some files were not shown because too many files have changed in this diff Show More