diff --git a/src/main/java/net/Indyuce/mmocore/api/Waypoint.java b/src/main/java/net/Indyuce/mmocore/api/Waypoint.java deleted file mode 100644 index 76a4c727..00000000 --- a/src/main/java/net/Indyuce/mmocore/api/Waypoint.java +++ /dev/null @@ -1,91 +0,0 @@ -package net.Indyuce.mmocore.api; - -import org.apache.commons.lang.Validate; -import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.World; -import org.bukkit.configuration.ConfigurationSection; -import org.bukkit.entity.Player; - -public class Waypoint { - private final String id, name; - private final Location loc; - private final double radiusSquared, stellium; - private final boolean def, sneak, dynamic; - - public Waypoint(ConfigurationSection section) { - Validate.notNull(section, "Could not load config section"); - - id = section.getName(); - - name = section.getString("name"); - Validate.notNull(name, "Could not load waypoint name"); - - String format = section.getString("location"); - Validate.notNull(format, "Could not read location"); - loc = readLocation(format); - - stellium = section.getDouble("stellium"); - radiusSquared = Math.pow(section.getDouble("radius"), 2); - def = section.getBoolean("default"); - sneak = !section.contains("sneak") || section.getBoolean("sneak"); - dynamic = section.getBoolean("dynamic"); - } - - public Location getLocation() { - return loc; - } - - public String getName() { - return name; - } - - public double getStelliumCost() { - return stellium; - } - - public boolean hasSneakEnabled() { - return sneak; - } - - public String getId() { - return id; - } - - public boolean isDefault() { - return def; - } - - public boolean isDynamic() { - return dynamic; - } - - public boolean isOnWaypoint(Player player) { - return player.getWorld().equals(loc.getWorld()) && player.getLocation().distanceSquared(loc) < radiusSquared; - } - - @Override - public String toString() { - return id; - } - - @Override - public boolean equals(Object object) { - return object instanceof Waypoint && ((Waypoint) object).id.equals(id); - } - - private Location readLocation(String string) { - String[] split = string.split(" "); - - World world = Bukkit.getWorld(split[0]); - Validate.notNull(world, "Could not find world with name '" + split[0]+"'"); - - double x = Double.parseDouble(split[1]); - double y = Double.parseDouble(split[2]); - double z = Double.parseDouble(split[3]); - float yaw = split.length > 4 ? (float) Double.parseDouble(split[4]) : 0; - float pitch = split.length > 5 ? (float) Double.parseDouble(split[5]) : 0; - - return new Location(world, x, y, z, yaw, pitch); - } -} \ No newline at end of file diff --git a/src/main/java/net/Indyuce/mmocore/api/event/PlayerResourceUpdateEvent.java b/src/main/java/net/Indyuce/mmocore/api/event/PlayerResourceUpdateEvent.java index a364a43f..291f4876 100644 --- a/src/main/java/net/Indyuce/mmocore/api/event/PlayerResourceUpdateEvent.java +++ b/src/main/java/net/Indyuce/mmocore/api/event/PlayerResourceUpdateEvent.java @@ -97,6 +97,11 @@ public class PlayerResourceUpdateEvent extends PlayerDataEvent implements Cancel */ SKILL_COST, + /** + * When consuming stellium to use a waypoint + */ + USE_WAYPOINT, + /** * Used by quests triggers * - {@link net.Indyuce.mmocore.api.quest.trigger.ManaTrigger} diff --git a/src/main/java/net/Indyuce/mmocore/api/player/PlayerData.java b/src/main/java/net/Indyuce/mmocore/api/player/PlayerData.java index 43c719e4..7d318220 100644 --- a/src/main/java/net/Indyuce/mmocore/api/player/PlayerData.java +++ b/src/main/java/net/Indyuce/mmocore/api/player/PlayerData.java @@ -6,7 +6,9 @@ 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.api.Waypoint; +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; @@ -22,7 +24,7 @@ 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.api.util.math.particle.SmallParticleEffect; +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; @@ -35,6 +37,7 @@ import net.Indyuce.mmocore.party.provided.Party; import net.Indyuce.mmocore.skill.ClassSkill; import net.Indyuce.mmocore.skill.RegisteredSkill; import net.Indyuce.mmocore.skill.cast.SkillCastingHandler; +import net.Indyuce.mmocore.waypoint.WaypointOption; import net.md_5.bungee.api.ChatMessageType; import net.md_5.bungee.api.chat.TextComponent; import org.apache.commons.lang.Validate; @@ -382,7 +385,7 @@ public class PlayerData extends OfflinePlayerData implements Closable, Experienc } public boolean hasWaypoint(Waypoint waypoint) { - return waypoint.isDefault() || waypoints.contains(waypoint.getId()); + return waypoint.hasOption(WaypointOption.DEFAULT) || waypoints.contains(waypoint.getId()); } public void unlockWaypoint(Waypoint waypoint) { @@ -455,9 +458,7 @@ public class PlayerData extends OfflinePlayerData implements Closable, Experienc * * @param waypoint Target waypoint */ - public void warp(Waypoint waypoint) { - if (!isOnline()) - return; + public void warp(Waypoint waypoint, CostType costType) { /* * This cooldown is only used internally to make sure the player is not @@ -466,7 +467,7 @@ public class PlayerData extends OfflinePlayerData implements Closable, Experienc */ setLastActivity(PlayerActivity.USE_WAYPOINT); - giveStellium(-waypoint.getStelliumCost(), PlayerResourceUpdateEvent.UpdateReason.SKILL_COST); + giveStellium(-waypoint.getCost(costType), PlayerResourceUpdateEvent.UpdateReason.USE_WAYPOINT); new BukkitRunnable() { final int x = getPlayer().getLocation().getBlockX(); @@ -481,7 +482,7 @@ public class PlayerData extends OfflinePlayerData implements Closable, Experienc || getPlayer().getLocation().getBlockZ() != z) { MMOCore.plugin.soundManager.getSound(SoundEvent.WARP_CANCELLED).playTo(getPlayer()); MMOCore.plugin.configManager.getSimpleMessage("warping-canceled").send(getPlayer()); - giveStellium(waypoint.getStelliumCost(), PlayerResourceUpdateEvent.UpdateReason.SKILL_REGENERATION); + giveStellium(waypoint.getCost(CostType.NORMAL_USE), PlayerResourceUpdateEvent.UpdateReason.SKILL_REGENERATION); cancel(); return; } diff --git a/src/main/java/net/Indyuce/mmocore/api/player/profess/PlayerClass.java b/src/main/java/net/Indyuce/mmocore/api/player/profess/PlayerClass.java index afded88e..3cd04908 100644 --- a/src/main/java/net/Indyuce/mmocore/api/player/profess/PlayerClass.java +++ b/src/main/java/net/Indyuce/mmocore/api/player/profess/PlayerClass.java @@ -14,7 +14,7 @@ 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.api.util.math.particle.CastingParticle; +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; diff --git a/src/main/java/net/Indyuce/mmocore/experience/PlayerProfessions.java b/src/main/java/net/Indyuce/mmocore/experience/PlayerProfessions.java index 4bcfb903..f7dd9963 100644 --- a/src/main/java/net/Indyuce/mmocore/experience/PlayerProfessions.java +++ b/src/main/java/net/Indyuce/mmocore/experience/PlayerProfessions.java @@ -12,7 +12,7 @@ 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.api.util.math.particle.SmallParticleEffect; +import net.Indyuce.mmocore.loot.chest.particle.SmallParticleEffect; import org.apache.commons.lang.Validate; import org.bukkit.Bukkit; import org.bukkit.ChatColor; diff --git a/src/main/java/net/Indyuce/mmocore/gui/WaypointViewer.java b/src/main/java/net/Indyuce/mmocore/gui/WaypointViewer.java index c4f598f7..307d9fef 100644 --- a/src/main/java/net/Indyuce/mmocore/gui/WaypointViewer.java +++ b/src/main/java/net/Indyuce/mmocore/gui/WaypointViewer.java @@ -3,7 +3,6 @@ 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.Waypoint; import net.Indyuce.mmocore.api.player.PlayerActivity; import net.Indyuce.mmocore.api.player.PlayerData; import net.Indyuce.mmocore.gui.api.EditableInventory; @@ -11,7 +10,9 @@ 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 org.apache.commons.lang.Validate; +import net.Indyuce.mmocore.waypoint.CostType; +import net.Indyuce.mmocore.waypoint.Waypoint; +import net.Indyuce.mmocore.waypoint.WaypointOption; import org.bukkit.Material; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.event.inventory.InventoryClickEvent; @@ -19,177 +20,202 @@ import org.bukkit.inventory.ItemStack; import java.util.ArrayList; import java.util.List; +import java.util.Objects; public class WaypointViewer extends EditableInventory { - public WaypointViewer() { - super("waypoints"); - } + public WaypointViewer() { + super("waypoints"); + } - @Override - public InventoryItem load(String function, ConfigurationSection config) { + @Override + public InventoryItem load(String function, ConfigurationSection config) { - if (function.equals("waypoint")) - return new WaypointItem(config); + if (function.equals("waypoint")) + return new WaypointItem(config); - if (function.equals("previous")) - return new SimplePlaceholderItem(config) { + if (function.equals("previous")) + return new SimplePlaceholderItem(config) { - @Override - public boolean canDisplay(WaypointViewerInventory inv) { - return inv.page > 0; - } - }; + @Override + public boolean canDisplay(WaypointViewerInventory inv) { + return inv.page > 0; + } + }; - if (function.equals("next")) - return new SimplePlaceholderItem(config) { + if (function.equals("next")) + return new SimplePlaceholderItem(config) { - @Override - public boolean canDisplay(WaypointViewerInventory inv) { - return inv.getEditable().getByFunction("waypoint").getSlots().size() * (inv.page + 1) < inv.waypoints.size(); - } - }; + @Override + public boolean canDisplay(WaypointViewerInventory inv) { + return inv.getEditable().getByFunction("waypoint").getSlots().size() * (inv.page + 1) < inv.waypoints.size(); + } + }; - return new SimplePlaceholderItem(config); - } + return new SimplePlaceholderItem(config); + } - public GeneratedInventory newInventory(PlayerData data) { - return newInventory(data, null); - } + public GeneratedInventory newInventory(PlayerData data) { + return newInventory(data, null); + } - public GeneratedInventory newInventory(PlayerData data, Waypoint waypoint) { - return new WaypointViewerInventory(data, this, waypoint); - } + public GeneratedInventory newInventory(PlayerData data, Waypoint waypoint) { + return new WaypointViewerInventory(data, this, waypoint); + } - public class WaypointDisplayItem extends InventoryItem { - private final Material notReady; + public class WaypointItem extends SimplePlaceholderItem { + private final SimplePlaceholderItem noWaypoint, locked; + private final WaypointItemHandler availWaypoint, notLinked, notDynamic, noStellium; - public WaypointDisplayItem(ConfigurationSection config) { - super(config); + public WaypointItem(ConfigurationSection config) { + super(Material.BARRIER, config); - Validate.isTrue(config.contains("not-ready"), "Could not read 'not-ready' material"); - notReady = Material.valueOf(config.getString("not-ready")); - } + noWaypoint = new SimplePlaceholderItem(Objects.requireNonNull(config.getConfigurationSection("no-waypoint"), "Could not load 'no-waypoint' config")); + locked = new SimplePlaceholderItem(Objects.requireNonNull(config.getConfigurationSection("locked"), "Could not load 'locked' config")); - @Override - public ItemStack display(WaypointViewerInventory inv, int n) { - ItemStack disp = super.display(inv, n); + notLinked = new WaypointItemHandler(Objects.requireNonNull(config.getConfigurationSection("not-a-destination"), "Could not load 'not-a-destination' config")); + notDynamic = new WaypointItemHandler(Objects.requireNonNull(config.getConfigurationSection("not-dynamic"), "Could not load 'not-dynamic' config")); + noStellium = new WaypointItemHandler(Objects.requireNonNull(config.getConfigurationSection("not-enough-stellium"), "Could not load 'not-enough-stellium' config")); + availWaypoint = new WaypointItemHandler(Objects.requireNonNull(config.getConfigurationSection("display"), "Could not load 'display' config")); + } - Waypoint waypoint = inv.waypoints.get(inv.page * inv.getEditable().getByFunction("waypoint").getSlots().size() + n); - if (inv.getPlayerData().getStellium() < waypoint.getStelliumCost() || (inv.current == null && !waypoint.isDynamic())) - disp.setType(notReady); + @Override + public boolean hasDifferentDisplay() { + return true; + } - return NBTItem.get(disp).addTag(new ItemTag("waypointId", waypoint.getId())).toItem(); - } + @Override + public ItemStack display(WaypointViewerInventory inv, int n) { - @Override - public Placeholders getPlaceholders(WaypointViewerInventory inv, int n) { - Placeholders holders = new Placeholders(); + int index = inv.page * inv.getEditable().getByFunction("waypoint").getSlots().size() + n; + if (index >= inv.waypoints.size()) + return noWaypoint.display(inv, n); - Waypoint waypoint = inv.waypoints.get(inv.page * inv.getByFunction("waypoint").getSlots().size() + n); - holders.register("name", waypoint.getName()); - holders.register("stellium", decimal.format(waypoint.getStelliumCost())); + // Locked waypoint? + Waypoint waypoint = inv.waypoints.get(index); + if (!inv.getPlayerData().hasWaypoint(waypoint)) + return locked.display(inv, n); - return holders; - } - } + // Waypoints are not linked + if (inv.current != null && !inv.current.hasDestination(waypoint)) + return notLinked.display(inv, n); - public class WaypointItem extends SimplePlaceholderItem { - private final SimplePlaceholderItem noWaypoint, locked; - private final WaypointDisplayItem availWaypoint; + // Not dynamic waypoint + if (inv.current == null && !waypoint.hasOption(WaypointOption.DYNAMIC)) + return notDynamic.display(inv, n); - public WaypointItem(ConfigurationSection config) { - super(Material.BARRIER, config); + // Stellium cost + if (waypoint.getCost(inv.current == null ? CostType.DYNAMIC_USE : CostType.NORMAL_USE) > inv.getPlayerData().getStellium()) + return noStellium.display(inv, n); - Validate.notNull(config.getConfigurationSection("no-waypoint"), "Could not load 'no-waypoint' config"); - Validate.notNull(config.getConfigurationSection("locked"), "Could not load 'locked' config"); - Validate.notNull(config.getConfigurationSection("display"), "Could not load 'display' config"); + return availWaypoint.display(inv, n); + } + } - noWaypoint = new SimplePlaceholderItem(config.getConfigurationSection("no-waypoint")); - locked = new SimplePlaceholderItem(config.getConfigurationSection("locked")); - availWaypoint = new WaypointDisplayItem(config.getConfigurationSection("display")); - } + public class WaypointItemHandler extends InventoryItem { + public WaypointItemHandler(ConfigurationSection config) { + super(config); + } - @Override - public boolean hasDifferentDisplay() { - return true; - } + @Override + public ItemStack display(WaypointViewerInventory inv, int n) { + ItemStack disp = super.display(inv, n); - @Override - public ItemStack display(WaypointViewerInventory inv, int n) { + // 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(); + } - int index = inv.page * inv.getEditable().getByFunction("waypoint").getSlots().size() + n; - if (index >= inv.waypoints.size()) - return noWaypoint.display(inv, n); + @Override + public Placeholders getPlaceholders(WaypointViewerInventory inv, int n) { + Placeholders holders = new Placeholders(); - Waypoint waypoint = inv.waypoints.get(index); - return inv.getPlayerData().hasWaypoint(waypoint) ? availWaypoint.display(inv, n) : locked.display(inv); - } - } + 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))); - public class WaypointViewerInventory extends GeneratedInventory { - private final List waypoints = new ArrayList<>(MMOCore.plugin.waypointManager.getAll()); - private final Waypoint current; + return holders; + } + } - private int page; + public class WaypointViewerInventory extends GeneratedInventory { + private final List waypoints = new ArrayList<>(MMOCore.plugin.waypointManager.getAll()); + private final Waypoint current; + private final CostType waypointCostType; - public WaypointViewerInventory(PlayerData playerData, EditableInventory editable, Waypoint current) { - super(playerData, editable); + private int page; - this.current = current; - } + public WaypointViewerInventory(PlayerData playerData, EditableInventory editable, Waypoint current) { + super(playerData, editable); - @Override - public String calculateName() { - return getName(); - } + this.current = current; + this.waypointCostType = current == null ? CostType.DYNAMIC_USE : CostType.NORMAL_USE; + } - @Override - public void whenClicked(InventoryClickEvent event, InventoryItem item) { - if (item.getFunction().equals("next")) { - page++; - open(); - return; - } + @Override + public String calculateName() { + return getName(); + } - if (item.getFunction().equals("previous")) { - page--; - open(); - return; - } + @Override + public void whenClicked(InventoryClickEvent event, InventoryItem item) { + if (item.getFunction().equals("next")) { + page++; + open(); + return; + } - if (item.getFunction().equals("waypoint")) { - String tag = NBTItem.get(event.getCurrentItem()).getString("waypointId"); - if (tag.equals("")) - return; + if (item.getFunction().equals("previous")) { + page--; + open(); + return; + } - Waypoint waypoint = MMOCore.plugin.waypointManager.get(tag); - if (!playerData.hasWaypoint(waypoint)) { - MMOCore.plugin.configManager.getSimpleMessage("not-unlocked-waypoint").send(player); - return; - } + if (item.getFunction().equals("waypoint")) { + String tag = NBTItem.get(event.getCurrentItem()).getString("waypointId"); + if (tag.equals("")) + return; - if (waypoint.equals(current)) { - MMOCore.plugin.configManager.getSimpleMessage("standing-on-waypoint").send(player); - return; - } + // Locked waypoint? + Waypoint waypoint = MMOCore.plugin.waypointManager.get(tag); + if (!playerData.hasWaypoint(waypoint)) { + MMOCore.plugin.configManager.getSimpleMessage("not-unlocked-waypoint").send(player); + return; + } - if (current == null && !waypoint.isDynamic()) { - MMOCore.plugin.configManager.getSimpleMessage("not-dynamic-waypoint").send(player); - return; - } + // Cannot teleport to current waypoint + if (waypoint.equals(current)) { + MMOCore.plugin.configManager.getSimpleMessage("standing-on-waypoint").send(player); + return; + } - double left = waypoint.getStelliumCost() - playerData.getStellium(); - if (left > 0) { - MMOCore.plugin.configManager.getSimpleMessage("not-enough-stellium", "more", decimal.format(left)).send(player); - return; - } + // Waypoint does not have target as destination + if (current != null && !current.hasDestination(waypoint)) { + MMOCore.plugin.configManager.getSimpleMessage("cannot-teleport-to").send(player); + return; + } - if (playerData.getActivityTimeOut(PlayerActivity.USE_WAYPOINT) > 0) - return; + // Not dynamic waypoint + if (current == null && !waypoint.hasOption(WaypointOption.DYNAMIC)) { + MMOCore.plugin.configManager.getSimpleMessage("not-dynamic-waypoint").send(player); + return; + } - player.closeInventory(); - playerData.warp(waypoint); - } - } - } + // Stellium cost + CostType costType = current == null ? CostType.DYNAMIC_USE : CostType.NORMAL_USE; + double left = waypoint.getCost(costType) - playerData.getStellium(); + if (left > 0) { + MMOCore.plugin.configManager.getSimpleMessage("not-enough-stellium", "more", decimal.format(left)).send(player); + return; + } + + if (playerData.getActivityTimeOut(PlayerActivity.USE_WAYPOINT) > 0) + return; + + player.closeInventory(); + playerData.warp(waypoint, costType); + } + } + } } diff --git a/src/main/java/net/Indyuce/mmocore/listener/WaypointsListener.java b/src/main/java/net/Indyuce/mmocore/listener/WaypointsListener.java index b95d7c7c..f49dc3ca 100644 --- a/src/main/java/net/Indyuce/mmocore/listener/WaypointsListener.java +++ b/src/main/java/net/Indyuce/mmocore/listener/WaypointsListener.java @@ -1,40 +1,58 @@ package net.Indyuce.mmocore.listener; +import io.lumine.mythic.lib.api.item.NBTItem; +import net.Indyuce.mmocore.MMOCore; import net.Indyuce.mmocore.api.SoundEvent; -import net.Indyuce.mmocore.manager.SoundManager; +import net.Indyuce.mmocore.api.player.PlayerData; +import net.Indyuce.mmocore.loot.chest.particle.SmallParticleEffect; +import net.Indyuce.mmocore.manager.InventoryManager; +import net.Indyuce.mmocore.waypoint.Waypoint; +import net.Indyuce.mmocore.waypoint.WaypointOption; import org.bukkit.Particle; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; +import org.bukkit.event.block.Action; +import org.bukkit.event.player.PlayerInteractEvent; import org.bukkit.event.player.PlayerToggleSneakEvent; -import net.Indyuce.mmocore.MMOCore; -import net.Indyuce.mmocore.api.Waypoint; -import net.Indyuce.mmocore.api.player.PlayerData; -import net.Indyuce.mmocore.api.util.math.particle.SmallParticleEffect; -import net.Indyuce.mmocore.manager.InventoryManager; +import java.util.Objects; public class WaypointsListener implements Listener { - @EventHandler - public void a(PlayerToggleSneakEvent event) { - Player player = event.getPlayer(); - if (!event.isSneaking()) - return; - Waypoint waypoint = MMOCore.plugin.waypointManager.getCurrentWaypoint(player); - if (waypoint == null || !waypoint.hasSneakEnabled()) - return; + @EventHandler + public void interactWithWaypoint(PlayerToggleSneakEvent event) { + Player player = event.getPlayer(); + if (!event.isSneaking()) + return; - PlayerData data = PlayerData.get(player); - if (!data.hasWaypoint(waypoint)) { - data.unlockWaypoint(waypoint); - new SmallParticleEffect(player, Particle.SPELL_WITCH); - MMOCore.plugin.configManager.getSimpleMessage("new-waypoint", "waypoint", waypoint.getName()).send(player); - MMOCore.plugin.soundManager.getSound(SoundEvent.WARP_UNLOCK).playTo(player); - return; - } + Waypoint waypoint = MMOCore.plugin.waypointManager.getCurrentWaypoint(player); + if (waypoint == null) + return; - player.setSneaking(false); - InventoryManager.WAYPOINTS.newInventory(data, waypoint).open(); - } + PlayerData data = PlayerData.get(player); + if (waypoint.hasOption(WaypointOption.UNLOCKABLE) && !data.hasWaypoint(waypoint)) { + data.unlockWaypoint(waypoint); + new SmallParticleEffect(player, Particle.SPELL_WITCH); + MMOCore.plugin.configManager.getSimpleMessage("new-waypoint", "waypoint", waypoint.getName()).send(player); + MMOCore.plugin.soundManager.getSound(SoundEvent.WARP_UNLOCK).playTo(player); + return; + } + + if (waypoint.hasOption(WaypointOption.ENABLE_MENU)) { + player.setSneaking(false); + InventoryManager.WAYPOINTS.newInventory(data, waypoint).open(); + } + } + + @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true) + public void waypointBook(PlayerInteractEvent event) { + if (!event.hasItem() || (event.getAction() != Action.RIGHT_CLICK_AIR && event.getAction() != Action.RIGHT_CLICK_BLOCK)) + return; + + NBTItem nbtItem = NBTItem.get(event.getItem()); + if (Objects.equals(nbtItem.getString("MMOCoreItemId"), "WAYPOINT_BOOK")) + InventoryManager.WAYPOINTS.newInventory(PlayerData.get(event.getPlayer())).open(); + } } diff --git a/src/main/java/net/Indyuce/mmocore/listener/profession/PlayerCollectStats.java b/src/main/java/net/Indyuce/mmocore/listener/profession/PlayerCollectStats.java index b27a618b..ce81b963 100644 --- a/src/main/java/net/Indyuce/mmocore/listener/profession/PlayerCollectStats.java +++ b/src/main/java/net/Indyuce/mmocore/listener/profession/PlayerCollectStats.java @@ -13,7 +13,7 @@ import org.bukkit.potion.PotionEffectType; import net.Indyuce.mmocore.api.event.CustomBlockMineEvent; import net.Indyuce.mmocore.api.player.stats.StatType; -import net.Indyuce.mmocore.api.util.math.particle.SmallParticleEffect; +import net.Indyuce.mmocore.loot.chest.particle.SmallParticleEffect; import io.lumine.mythic.lib.MythicLib; public class PlayerCollectStats implements Listener { diff --git a/src/main/java/net/Indyuce/mmocore/manager/WaypointManager.java b/src/main/java/net/Indyuce/mmocore/manager/WaypointManager.java index 16236878..244a68e3 100644 --- a/src/main/java/net/Indyuce/mmocore/manager/WaypointManager.java +++ b/src/main/java/net/Indyuce/mmocore/manager/WaypointManager.java @@ -9,7 +9,7 @@ import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.entity.Player; import net.Indyuce.mmocore.MMOCore; -import net.Indyuce.mmocore.api.Waypoint; +import net.Indyuce.mmocore.waypoint.Waypoint; public class WaypointManager { private final Map waypoints = new LinkedHashMap<>(); diff --git a/src/main/java/net/Indyuce/mmocore/api/player/Unlockable.java b/src/main/java/net/Indyuce/mmocore/player/Unlockable.java similarity index 79% rename from src/main/java/net/Indyuce/mmocore/api/player/Unlockable.java rename to src/main/java/net/Indyuce/mmocore/player/Unlockable.java index 3ec06f74..8cf75544 100644 --- a/src/main/java/net/Indyuce/mmocore/api/player/Unlockable.java +++ b/src/main/java/net/Indyuce/mmocore/player/Unlockable.java @@ -1,4 +1,6 @@ -package net.Indyuce.mmocore.api.player; +package net.Indyuce.mmocore.player; + +import net.Indyuce.mmocore.api.player.PlayerData; /** * Some item that can be unlocked diff --git a/src/main/java/net/Indyuce/mmocore/tree/SkillTreeNode.java b/src/main/java/net/Indyuce/mmocore/tree/SkillTreeNode.java index 2ef69251..1d8025e4 100644 --- a/src/main/java/net/Indyuce/mmocore/tree/SkillTreeNode.java +++ b/src/main/java/net/Indyuce/mmocore/tree/SkillTreeNode.java @@ -3,7 +3,7 @@ package net.Indyuce.mmocore.tree; import io.lumine.mythic.lib.MythicLib; import io.lumine.mythic.lib.player.modifier.PlayerModifier; import io.lumine.mythic.lib.util.configobject.ConfigSectionObject; -import net.Indyuce.mmocore.api.player.Unlockable; +import net.Indyuce.mmocore.player.Unlockable; import org.apache.commons.lang.Validate; import org.bukkit.configuration.ConfigurationSection; diff --git a/src/main/java/net/Indyuce/mmocore/waypoint/CostType.java b/src/main/java/net/Indyuce/mmocore/waypoint/CostType.java new file mode 100644 index 00000000..64719615 --- /dev/null +++ b/src/main/java/net/Indyuce/mmocore/waypoint/CostType.java @@ -0,0 +1,29 @@ +package net.Indyuce.mmocore.waypoint; + +public enum CostType { + + /** + * When teleporting to this waypoint + */ + NORMAL_USE, + + /** + * When dynamically teleporting to this waypoint + */ + DYNAMIC_USE, + + /** + * When setting your spawn point to this waypoint. + */ + SET_SPAWNPOINT; + + private final String path; + + CostType() { + this.path = name().toLowerCase().replace("_", "-"); + } + + public String getPath() { + return path; + } +} diff --git a/src/main/java/net/Indyuce/mmocore/waypoint/Waypoint.java b/src/main/java/net/Indyuce/mmocore/waypoint/Waypoint.java new file mode 100644 index 00000000..f6d609b7 --- /dev/null +++ b/src/main/java/net/Indyuce/mmocore/waypoint/Waypoint.java @@ -0,0 +1,121 @@ +package net.Indyuce.mmocore.waypoint; + +import net.Indyuce.mmocore.player.Unlockable; +import org.apache.commons.lang.Validate; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.entity.Player; + +import java.util.*; + +public class Waypoint implements Unlockable { + private final String id, name; + private final Location loc; + private final double radiusSquared; + + /** + * Set that saves all the waypoints accessible when in this waypoint. + * This turns the waypoints system into a giant network. + *

+ * If it's empty it can access any waypoint. + */ + private final Set destinations = new HashSet<>(); + + /** + * Waypoint options saved here. + */ + private final Map options = new HashMap<>(); + + /** + * Stellium cost for each action (0 being the default cost) + */ + private final Map costs = new HashMap<>(); + + public Waypoint(ConfigurationSection config) { + id = Objects.requireNonNull(config, "Could not load config section").getName(); + name = Objects.requireNonNull(config.getString("name"), "Could not load waypoint name"); + + loc = readLocation(Objects.requireNonNull(config.getString("location"), "Could not read location")); + radiusSquared = Math.pow(config.getDouble("radius"), 2); + + for (CostType costType : CostType.values()) + costs.put(costType, config.getDouble("cost." + costType.getPath())); + + for (WaypointOption option : WaypointOption.values()) + options.put(option, config.getBoolean("option." + option.getPath(), option.getDefaultValue())); + + destinations.addAll(config.getStringList("linked")); + } + + public String getId() { + return id; + } + + public String getName() { + return name; + } + + public Location getLocation() { + return loc; + } + + /** + * @param other Another waypoint + * @return If any player standing on that waypoint can teleport to given waypoint + */ + public boolean hasDestination(Waypoint other) { + return destinations.isEmpty() || destinations.contains(other.getId()); + } + + public double getCost(CostType type) { + return costs.getOrDefault(type, 0d); + } + + public boolean hasOption(WaypointOption option) { + return options.get(option); + } + + public boolean isOnWaypoint(Player player) { + return player.getWorld().equals(loc.getWorld()) && player.getLocation().distanceSquared(loc) < radiusSquared; + } + + @Override + public String toString() { + return id; + } + + @Override + public String getUnlockNamespacedKey() { + return "waypoint:" + getId(); + } + + @Override + public int hashCode() { + return Objects.hash(id); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Waypoint waypoint = (Waypoint) o; + return id.equals(waypoint.id); + } + + private Location readLocation(String string) { + String[] split = string.split(" "); + + World world = Bukkit.getWorld(split[0]); + Validate.notNull(world, "Could not find world with name '" + split[0] + "'"); + + double x = Double.parseDouble(split[1]); + double y = Double.parseDouble(split[2]); + double z = Double.parseDouble(split[3]); + float yaw = split.length > 4 ? (float) Double.parseDouble(split[4]) : 0; + float pitch = split.length > 5 ? (float) Double.parseDouble(split[5]) : 0; + + return new Location(world, x, y, z, yaw, pitch); + } +} \ No newline at end of file diff --git a/src/main/java/net/Indyuce/mmocore/waypoint/WaypointOption.java b/src/main/java/net/Indyuce/mmocore/waypoint/WaypointOption.java new file mode 100644 index 00000000..65a3b582 --- /dev/null +++ b/src/main/java/net/Indyuce/mmocore/waypoint/WaypointOption.java @@ -0,0 +1,46 @@ +package net.Indyuce.mmocore.waypoint; + +public enum WaypointOption { + + DEFAULT(false), + + /** + * Enable this so make the waypoint auto unlock when you sneak on it. + */ + UNLOCKABLE(true), + + /** + * When enabled players can sneak when standing on that waypoint + * to open its menu. This option can be disabled to create waypoints + * that you can only teleport to. + */ + ENABLE_MENU(true), + + /** + * By defaut, players must stand into + */ + DYNAMIC(false), + + /** + * When set to true, players can choose this waypoint as their spawnpoint. + * This action costs some stellium. + */ + // SPAWNABLE(false) + ; + + private final String path; + private final boolean defaultValue; + + WaypointOption(boolean defaultValue) { + this.path = name().toLowerCase().replace("_", "-"); + this.defaultValue = defaultValue; + } + + public String getPath() { + return path; + } + + public boolean getDefaultValue() { + return defaultValue; + } +} diff --git a/src/main/resources/default/gui/waypoints.yml b/src/main/resources/default/gui/waypoints.yml index 6d5a2c58..074e6aca 100644 --- a/src/main/resources/default/gui/waypoints.yml +++ b/src/main/resources/default/gui/waypoints.yml @@ -1,51 +1,79 @@ - # GUI display name name: Waypoints +name-on-waypoint: 'Waypoint: {waypoint}' # Number of slots in your inventory. Must be # between 9 and 54 and must be a multiple of 9. slots: 45 items: - waypoint: - slots: [10,11,12,13,14,15,16,19,20,21,22,23,24,25,28,29,30,31,32,33,34] - function: waypoint - - # Displayed when there is no waypoint - no-waypoint: - item: GRAY_STAINED_GLASS_PANE - name: '&a' - lore: {} - - # Displayed when the waypoint has not been unlocked yet. - locked: - name: '&c- Locked -' - item: GRAY_DYE - lore: {} - - # Displayed when the waypoint is unlocked. - display: - name: '&a{name}' - item: ENDER_EYE - - # Material displayed when the waypoint is not - # ready (not dynamic, or not enough stellium) - not-ready: ENDER_PEARL - - lore: - - '&7You have unlocked this waypoint.' - - '&7Click to teleport for &b{stellium} &7stellium.' - next: - slots: [26] - function: next - item: PLAYER_HEAD - texture: eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMTliZjMyOTJlMTI2YTEwNWI1NGViYTcxM2FhMWIxNTJkNTQxYTFkODkzODgyOWM1NjM2NGQxNzhlZDIyYmYifX19 - name: '&aNext Page' - lore: [] - previous: - slots: [18] - function: previous - item: PLAYER_HEAD - texture: eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYmQ2OWUwNmU1ZGFkZmQ4NGU1ZjNkMWMyMTA2M2YyNTUzYjJmYTk0NWVlMWQ0ZDcxNTJmZGM1NDI1YmMxMmE5In19fQ== - name: '&aPrevious Page' - lore: [] \ No newline at end of file + waypoint: + slots: [ 10,11,12,13,14,15,16,19,20,21,22,23,24,25,28,29,30,31,32,33,34 ] + function: waypoint + + # Displayed when there is no waypoint + no-waypoint: + item: GRAY_STAINED_GLASS_PANE + name: '&a' + lore: { } + + # Displayed when the waypoint has not been unlocked yet. + locked: + name: '&c- Locked -' + item: GRAY_DYE + lore: { } + + # When the two waypoints are not linked together + not-a-destination: + name: '&a{name}' + item: ENDER_PEARL + + # Material displayed when the waypoint is not + # ready (not dynamic, or not enough stellium) + not-ready: ENDER_PEARL + + lore: + - '&7You cannot teleport as the two waypoints are not linked.' + - '&7Teleporting costs &b&l{normal_cost}&7/&b&l{dynamic_cost} &7Stellium.' + + # When you cannot teleport to a non dynamic waypoint + not-dynamic: + name: '&a{name}' + item: ENDER_PEARL + + lore: + - '&7You cannot teleport as you are not standing on a waypoint.' + - '&7Teleporting costs &b&l{normal_cost}&7/&b&l{dynamic_cost} &7Stellium.' + + # When you cannot teleport to a non dynamic waypoint + not-enough-stellium: + name: '&a{name}' + item: ENDER_PEARL + + lore: + - '&7You cannot teleport as you do not have enough Stellium.' + - '&7Teleporting costs &b&l{normal_cost}&7/&b&l{dynamic_cost} &7Stellium.' + + # Displayed when the waypoint is unlocked and usable + display: + name: '&a{name}' + item: ENDER_EYE + + lore: + - '&7You can teleport to this waypoint.' + - '&7Click to teleport for &b{current_cost} &7Stellium.' + + next: + slots: [ 26 ] + function: next + item: PLAYER_HEAD + texture: eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMTliZjMyOTJlMTI2YTEwNWI1NGViYTcxM2FhMWIxNTJkNTQxYTFkODkzODgyOWM1NjM2NGQxNzhlZDIyYmYifX19 + name: '&aNext Page' + lore: [ ] + previous: + slots: [ 18 ] + function: previous + item: PLAYER_HEAD + texture: eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYmQ2OWUwNmU1ZGFkZmQ4NGU1ZjNkMWMyMTA2M2YyNTUzYjJmYTk0NWVlMWQ0ZDcxNTJmZGM1NDI1YmMxMmE5In19fQ== + name: '&aPrevious Page' + lore: [ ] \ No newline at end of file diff --git a/src/main/resources/default/items.yml b/src/main/resources/default/items.yml index 1c98c533..05de0cbe 100644 --- a/src/main/resources/default/items.yml +++ b/src/main/resources/default/items.yml @@ -1,29 +1,35 @@ - GOLD_COIN: - item: GOLD_NUGGET - name: '&6Gold Coin' - lore: + item: GOLD_NUGGET + name: '&6Gold Coin' + lore: - '&eWorth: 1g' NOTE: - item: PAPER - name: '&6Note' - lore: + item: PAPER + name: '&6Note' + lore: - '&eWorth: {worth}g' +WAYPOINT_BOOK: + item: ENCHANTED_BOOK + name: '&6Waypoints Book' + lore: + - '&7Waypoints are locations used to save your progress.' + - '&7This book gives you the ability to freely warp between these.' + DEPOSIT_ITEM: - item: BOOK - name: '&eDeposit {worth}g' - lore: {} + item: BOOK + name: '&eDeposit {worth}g' + lore: { } GOLD_POUCH: - item: LEATHER - name: '&fGold Pouch' - lore: + item: LEATHER + name: '&fGold Pouch' + lore: - '&7Right-Click to open.' MOB_GOLD_POUCH: - item: LEATHER - name: '&fGold Pouch' - lore: + item: LEATHER + name: '&fGold Pouch' + lore: - '&7Right-Click to open.' diff --git a/src/main/resources/default/messages.yml b/src/main/resources/default/messages.yml index 209e4727..e15a1895 100644 --- a/src/main/resources/default/messages.yml +++ b/src/main/resources/default/messages.yml @@ -73,6 +73,7 @@ not-dynamic-waypoint: '&cYou many only teleport to a non-dynamic waypoint while standing-on-waypoint: '&cYou are already standing on this waypoint.' warping-canceled: '%&cWaypoint warping canceled.' warping-comencing: '%&cDO NOT MOVE!&e You will be warped in {left}sec.' +cannot-teleport-to: '&cThe two waypoints are not linked.' # Cash deposit: '&eYou successfully deposited &6{worth}g&e.' diff --git a/src/main/resources/default/waypoints.yml b/src/main/resources/default/waypoints.yml index 30eeb7b7..8613282a 100644 --- a/src/main/resources/default/waypoints.yml +++ b/src/main/resources/default/waypoints.yml @@ -1,45 +1,58 @@ - -# Waypoint ID, used as reference. -# Make sure the waypoints have different IDs. +# Waypoint identifier, used as reference for admin commands. +# Make sure all the waypoints have different identifiers. spawn: - # Name of waypoint displayed in the waypoint GUI. - name: Spawn - - # Location of waypoint: - # Yaw and pitch are where the player will be looking at when teleported. - location: 'world 69 71 136 136 0' - - # Radius of waypoint around the specified location. - radius: 1.5 - + # Name of waypoint displayed in the waypoint GUI. + name: Spawn + + # Location of waypoint: + # Yaw and pitch are where the player will be looking at when teleported. + location: 'world 69 71 136 136 0' + + # Radius of waypoint around the specified location. + radius: 2.0 + + cost: + # Stellium cost in order to use the waypoint. # Stellium is like stamina however it's not used # by skills and regens much slower than mana. - stellium: 3 - + normal-use: 3 + + # Cost when not standing on any waypoint. + dynamic-use: 5 + + option: + # When enabled, players can unlock the waypoint - # by sneaking on it, and can open the waypoint menu - # from the specified location (true by default). - sneak: true - + # by sneaking on it (true by default) + unlockable: true + + # When enabled, players can teleport to other + #waypoints when sneaking (true by default) + enable-menu: true + # Should be waypoint be unlocked by default? default: true spawn1: - name: Spawn1 - location: 'world 69 71 136 136 0' - radius: 1.5 - stellium: 3 + name: Spawn1 + location: 'world 69 71 136 136 0' + radius: 2.0 + cost: + normal-use: 3 + option: default: false - + # Can be teleported to even when not standing # on any waypoint (waypoint must be unlocked). dynamic: true spawn2: - name: Spawn2 - location: 'world 69 71 136 136 0' - radius: 1.5 - stellium: 3 - sneak: false + name: Spawn2 + location: 'world 69 71 136 136 0' + radius: 3.0 + cost: + normal-use: 3 + option: + enable-menu: false