diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..fc4ca94 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +.gradle +.idea +build +target diff --git a/BattlePass.iml b/BattlePass.iml new file mode 100644 index 0000000..a589521 --- /dev/null +++ b/BattlePass.iml @@ -0,0 +1,13 @@ + + + + + + + SPIGOT + + 1 + + + + \ No newline at end of file diff --git a/src/main/java/com/Lino/battlePass/BattlePass.java b/src/main/java/com/Lino/battlePass/BattlePass.java index 908f4e3..2bd08a7 100644 --- a/src/main/java/com/Lino/battlePass/BattlePass.java +++ b/src/main/java/com/Lino/battlePass/BattlePass.java @@ -92,6 +92,8 @@ public void run() { coinsDistributionTask = new CoinsDistributionTask(BattlePass.this); if (nextDist != null) { coinsDistributionTask.setNextDistribution(nextDist); + } else { + coinsDistributionTask.resetDistributionTime(); } coinsDistributionTask.runTaskTimer(BattlePass.this, 200L, 1200L); }); @@ -99,7 +101,7 @@ public void run() { registerPlaceholders(); checkForUpdates(); - getLogger().info(messageManager.getMessage("messages.plugin-enabled")); + getLogger().info("✓ Battle Pass enabled successfully!"); this.cancel(); } else if (attempts >= MAX_ATTEMPTS) { getLogger().severe("Failed to initialize MissionManager after 30 seconds!"); @@ -216,7 +218,7 @@ public void reload() { boolean isBattlePassGUI = false; int currentPage = 1; - for (int i = 1; i <= 6; i++) { + for (int i = 1; i <= rewardManager.getMaxPage(); i++) { if (title.equals(messageManager.getMessage("gui.battlepass", "%page%", String.valueOf(i)))) { isBattlePassGUI = true; currentPage = i; diff --git a/src/main/java/com/Lino/battlePass/commands/BattlePassCommand.java b/src/main/java/com/Lino/battlePass/commands/BattlePassCommand.java index ce0e7c0..aac597b 100644 --- a/src/main/java/com/Lino/battlePass/commands/BattlePassCommand.java +++ b/src/main/java/com/Lino/battlePass/commands/BattlePassCommand.java @@ -266,7 +266,7 @@ private boolean handleXPCommand(CommandSender sender, String[] args, boolean add totalXP = Math.max(0, totalXP - amount); int newLevel = 1; - while (totalXP >= xpPerLevel && newLevel < 54) { + while (totalXP >= xpPerLevel && newLevel < plugin.getRewardManager().getMaxLevel()) { totalXP -= xpPerLevel; newLevel++; } @@ -480,7 +480,7 @@ private boolean handleGiveItemCommand(CommandSender sender, String[] args) { private void checkLevelUp(Player player, PlayerData data, int xpPerLevel) { boolean leveled = false; - while (data.xp >= xpPerLevel && data.level < 54) { + while (data.xp >= xpPerLevel && data.level < plugin.getRewardManager().getMaxLevel()) { data.xp -= xpPerLevel; data.level++; data.totalLevels++; @@ -491,7 +491,7 @@ private void checkLevelUp(Player player, PlayerData data, int xpPerLevel) { "%level%", String.valueOf(data.level))); player.playSound(player.getLocation(), Sound.UI_TOAST_CHALLENGE_COMPLETE, 1.0f, 1.0f); - int available = plugin.getRewardManager().countAvailableRewards(player, data); + int available = plugin.getRewardManager().countAvailableRewards(data); if (available > 0) { player.sendMessage(plugin.getMessageManager().getPrefix() + plugin.getMessageManager().getMessage("messages.new-rewards")); diff --git a/src/main/java/com/Lino/battlePass/gui/BattlePassGui.java b/src/main/java/com/Lino/battlePass/gui/BattlePassGui.java index 499a761..650a7c7 100644 --- a/src/main/java/com/Lino/battlePass/gui/BattlePassGui.java +++ b/src/main/java/com/Lino/battlePass/gui/BattlePassGui.java @@ -56,6 +56,7 @@ private void setupProgressItem(Inventory gui) { .replace("%level%", String.valueOf(playerData.level)) .replace("%xp%", String.valueOf(playerData.xp)) .replace("%xp_needed%", String.valueOf(plugin.getConfigManager().getXpPerLevel())) + .replace("%max_level%", String.valueOf(maxLevel)) .replace("%premium_status%", premiumStatus) .replace("%season_time%", plugin.getMissionManager().getTimeUntilSeasonEnd()); lore.add(GradientColorParser.parse(processedLine)); @@ -209,8 +210,7 @@ private void setupNavigationButtons(Inventory gui) { gui.setItem(45, createNavigationItem(false, page - 1)); } - int maxPages = (int) Math.ceil(maxLevel / 9.0); - if (page < maxPages) { + if (page < plugin.getRewardManager().getMaxPage()) { gui.setItem(53, createNavigationItem(true, page + 1)); } } diff --git a/src/main/java/com/Lino/battlePass/gui/RewardsEditorGui.java b/src/main/java/com/Lino/battlePass/gui/RewardsEditorGui.java index 781d55b..e3c2020 100644 --- a/src/main/java/com/Lino/battlePass/gui/RewardsEditorGui.java +++ b/src/main/java/com/Lino/battlePass/gui/RewardsEditorGui.java @@ -28,6 +28,7 @@ public void open() { } Inventory gui = createInventory(); + String maxLevel = String.valueOf(plugin.getRewardManager().getMaxLevel()); ItemStack freeRewards = new ItemStack(Material.CHEST); ItemMeta freeMeta = freeRewards.getItemMeta(); @@ -39,7 +40,7 @@ public void open() { freeLore.add(GradientColorParser.parse("&7that all players can claim")); freeLore.add(""); freeLore.add(GradientColorParser.parse("▼ Features ▼")); - freeLore.add(GradientColorParser.parse("&7• View all 54 levels")); + freeLore.add(GradientColorParser.parse("&7• View all %max_level% levels".replace("%max_level%", maxLevel))); freeLore.add(GradientColorParser.parse("&7• Add/remove items")); freeLore.add(GradientColorParser.parse("&7• Configure commands")); freeLore.add(""); @@ -59,7 +60,7 @@ public void open() { premiumLore.add(GradientColorParser.parse("&7exclusive to premium pass holders")); premiumLore.add(""); premiumLore.add(GradientColorParser.parse("▼ Features ▼")); - premiumLore.add(GradientColorParser.parse("&7• View all 54 levels")); + premiumLore.add(GradientColorParser.parse("&7• View all %max_level% levels".replace("%max_level%", maxLevel))); premiumLore.add(GradientColorParser.parse("&7• Add/remove items")); premiumLore.add(GradientColorParser.parse("&7• Configure commands")); premiumLore.add(""); diff --git a/src/main/java/com/Lino/battlePass/listeners/CustomItemsListener.java b/src/main/java/com/Lino/battlePass/listeners/CustomItemsListener.java index cefaabc..c9e0303 100644 --- a/src/main/java/com/Lino/battlePass/listeners/CustomItemsListener.java +++ b/src/main/java/com/Lino/battlePass/listeners/CustomItemsListener.java @@ -171,7 +171,7 @@ private void handleLevelBoostUse(PlayerInteractEvent event, Player player) { } if (levelsGained > 0) { - int available = plugin.getRewardManager().countAvailableRewards(player, data); + int available = plugin.getRewardManager().countAvailableRewards(data); if (available > 0) { player.sendMessage(plugin.getMessageManager().getPrefix() + plugin.getMessageManager().getMessage("messages.new-rewards")); diff --git a/src/main/java/com/Lino/battlePass/listeners/GuiClickListener.java b/src/main/java/com/Lino/battlePass/listeners/GuiClickListener.java index 5113c40..a7442d1 100644 --- a/src/main/java/com/Lino/battlePass/listeners/GuiClickListener.java +++ b/src/main/java/com/Lino/battlePass/listeners/GuiClickListener.java @@ -85,8 +85,7 @@ private void handleBattlePassClick(Player player, ItemStack clicked, int slot) { String action = meta.getPersistentDataContainer().get(plugin.getEventManager().getNavigationKey(), PersistentDataType.STRING); // Calcolo dinamico delle pagine massime - int maxLevel = plugin.getRewardManager().getMaxLevel(); - int maxPages = (int) Math.ceil(maxLevel / 9.0); + int maxPages = plugin.getRewardManager().getMaxPage(); if (maxPages < 1) maxPages = 1; if ("previous".equals(action) && currentPage > 1) { @@ -197,21 +196,19 @@ private void handleDailyRewardClaim(Player player, int currentPage) { data.lastDailyReward = now; int xpPerLevel = plugin.getConfigManager().getXpPerLevel(); - boolean leveled = false; int maxLevel = plugin.getRewardManager().getMaxLevel(); while (data.xp >= xpPerLevel && data.level < maxLevel) { data.xp -= xpPerLevel; data.level++; data.totalLevels++; - leveled = true; player.sendMessage(plugin.getMessageManager().getPrefix() + plugin.getMessageManager().getMessage("messages.level-up", "%level%", String.valueOf(data.level))); player.playSound(player.getLocation(), Sound.UI_TOAST_CHALLENGE_COMPLETE, 1.0f, 1.0f); - int available = plugin.getRewardManager().countAvailableRewards(player, data); + int available = plugin.getRewardManager().countAvailableRewards(data); if (available > 0) { player.sendMessage(plugin.getMessageManager().getPrefix() + plugin.getMessageManager().getMessage("messages.new-rewards")); diff --git a/src/main/java/com/Lino/battlePass/listeners/MissionEditorListener.java b/src/main/java/com/Lino/battlePass/listeners/MissionEditorListener.java index d2490ed..46b44c9 100644 --- a/src/main/java/com/Lino/battlePass/listeners/MissionEditorListener.java +++ b/src/main/java/com/Lino/battlePass/listeners/MissionEditorListener.java @@ -123,7 +123,7 @@ private void handleDetailsClick(Player player, InventoryClickEvent event, String if (slot == 12) { ConfigurationSection section = plugin.getConfigManager().getMissionsConfig().getConfigurationSection("mission-pools." + key); if (section != null) { - String missionType = section.getString("type"); + String missionType = section.getString("type", "UNKNOWN"); isTargetRequired = plugin.getMissionEditorManager().isTargetRequired(missionType); } } diff --git a/src/main/java/com/Lino/battlePass/listeners/MissionProgressListener.java b/src/main/java/com/Lino/battlePass/listeners/MissionProgressListener.java index 137c4be..0a4ef23 100644 --- a/src/main/java/com/Lino/battlePass/listeners/MissionProgressListener.java +++ b/src/main/java/com/Lino/battlePass/listeners/MissionProgressListener.java @@ -4,8 +4,7 @@ import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.Material; -import org.bukkit.entity.EntityType; -import org.bukkit.entity.Player; +import org.bukkit.entity.*; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; @@ -15,9 +14,13 @@ import org.bukkit.event.entity.*; import org.bukkit.event.inventory.CraftItemEvent; import org.bukkit.event.inventory.FurnaceExtractEvent; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.event.inventory.InventoryType; import org.bukkit.event.player.*; import org.bukkit.inventory.ItemStack; +import org.bukkit.projectiles.ProjectileSource; +import java.lang.reflect.Method; import java.util.*; import java.util.concurrent.ConcurrentHashMap; @@ -25,6 +28,7 @@ public class MissionProgressListener implements Listener { private final BattlePass plugin; private final Map lastLocations = new ConcurrentHashMap<>(); + private final Map distanceBuffer = new ConcurrentHashMap<>(); private final Set oreTypes = EnumSet.noneOf(Material.class); private final Map> recentlyPlacedBlocks = new ConcurrentHashMap<>(); @@ -36,7 +40,7 @@ public MissionProgressListener(BattlePass plugin) { private void initializeOreTypes() { for (Material mat : Material.values()) { String name = mat.name(); - if (name.endsWith("_ORE") || name.equals("ANCIENT_DEBRIS") || name.equals("NETHER_QUARTZ_ORE") || name.equals("GILDED_BLACKSTONE")) { + if (name.endsWith("_ORE") || name.equals("ANCIENT_DEBRIS") || name.equals("GILDED_BLACKSTONE")) { oreTypes.add(mat); } } @@ -69,9 +73,12 @@ public void onPlayerTeleport(PlayerTeleportEvent event) { @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onPlayerMove(PlayerMoveEvent event) { - if (event.getFrom().getBlockX() == event.getTo().getBlockX() && - event.getFrom().getBlockY() == event.getTo().getBlockY() && - event.getFrom().getBlockZ() == event.getTo().getBlockZ()) { + Location from = event.getFrom(); + Location to = event.getTo(); + + if (from.getBlockX() == to.getBlockX() + && from.getBlockY() == to.getBlockY() + && from.getBlockZ() == to.getBlockZ()) { return; } @@ -79,50 +86,90 @@ public void onPlayerMove(PlayerMoveEvent event) { UUID uuid = player.getUniqueId(); Location last = lastLocations.get(uuid); - Location toLoc = event.getTo(); + if (last == null) { + lastLocations.put(uuid, to); + return; + } + + if (last.getWorld() == null || to.getWorld() == null + || !last.getWorld().getName().equals(to.getWorld().getName())) { + lastLocations.put(uuid, to); + distanceBuffer.remove(uuid); + return; + } + + double distance; + try { + distance = last.distance(to); + } catch (IllegalArgumentException e) { + lastLocations.put(uuid, to); + distanceBuffer.remove(uuid); + return; + } + + if (distance > 0 && distance < 100) { - if (last != null) { - if (last.getWorld() == null || toLoc.getWorld() == null || - !last.getWorld().getName().equals(toLoc.getWorld().getName())) { - lastLocations.put(uuid, toLoc); - return; + String mode; + if (player.isFlying() || player.isGliding()) { + mode = "FLY"; + } else if (player.isSwimming() || player.getLocation().getBlock().isLiquid()) { + mode = "SWIM"; + } else if (player.isSneaking()) { + mode = "SNEAK"; + } else { + mode = "WALK"; } - try { - double distance = last.distance(toLoc); - if (distance >= 1 && distance < 100) { - plugin.getMissionManager().progressMission(player, "WALK_DISTANCE", "ANY", (int) distance); - } - } catch (IllegalArgumentException e) { + double buf = distanceBuffer.getOrDefault(uuid, 0.0); + buf += distance; + int whole = (int) buf; + if (whole > 0) { + plugin.getMissionManager().progressMission(player, "WALK_DISTANCE", mode, whole); + buf -= whole; } - lastLocations.put(uuid, toLoc); - } else { - lastLocations.put(uuid, toLoc); + distanceBuffer.put(uuid, buf); } + + lastLocations.put(uuid, to); } @EventHandler(priority = EventPriority.MONITOR) public void onPlayerDeath(PlayerDeathEvent event) { - plugin.getMissionManager().progressMission(event.getEntity(), "DEATH", "ANY", 1); + Player player = event.getEntity(); + EntityDamageEvent last = player.getLastDamageCause(); + if (last == null) { + plugin.getMissionManager().progressMission(player, "DEATH", "UNKNOWN", 1); + return; + } + + for (String type : enumerateDamageTypes(last)) { + plugin.getMissionManager().progressMission(player, "DEATH", type, 1); + } } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) - public void onEntityDamageByEntity(EntityDamageByEntityEvent event) { - if (event.getDamager() instanceof Player) { - Player player = (Player) event.getDamager(); - plugin.getMissionManager().progressMission(player, "DAMAGE_DEALT", "ANY", (int) event.getDamage()); + public void onEntityDamage(EntityDamageEvent event) { + if (!(event.getEntity() instanceof Player player)) return; + int amount = (int) event.getFinalDamage(); + + for (String type : enumerateDamageTypes(event)) { + plugin.getMissionManager().progressMission(player, "DAMAGE_TAKEN", type, amount); } + } - if (event.getEntity() instanceof Player) { - Player player = (Player) event.getEntity(); - plugin.getMissionManager().progressMission(player, "DAMAGE_TAKEN", "ANY", (int) event.getDamage()); + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onEntityDamageByEntity(EntityDamageByEntityEvent event) { + Entity trueDamager = getTrueDamager(event.getDamager()); + if (trueDamager instanceof Player player) { + int amount = (int) Math.round(event.getFinalDamage()); + String victimType = safeName(event.getEntity().getType().name()); + plugin.getMissionManager().progressMission(player, "DAMAGE_DEALT", victimType, amount); } } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onEntityBreed(EntityBreedEvent event) { - if (event.getBreeder() instanceof Player) { - Player player = (Player) event.getBreeder(); + if (event.getBreeder() instanceof Player player) { String entityType = event.getEntity().getType().name(); plugin.getMissionManager().progressMission(player, "BREED_ANIMAL", entityType, 1); } @@ -130,32 +177,42 @@ public void onEntityBreed(EntityBreedEvent event) { @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onEntityTame(EntityTameEvent event) { - if (event.getOwner() instanceof Player) { - Player player = (Player) event.getOwner(); + if (event.getOwner() instanceof Player player) { String entityType = event.getEntity().getType().name(); plugin.getMissionManager().progressMission(player, "TAME_ANIMAL", entityType, 1); } } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) - public void onVillagerTrade(PlayerInteractEntityEvent event) { - if (event.getRightClicked().getType() == EntityType.VILLAGER) { - Player player = event.getPlayer(); - plugin.getMissionManager().progressMission(player, "TRADE_VILLAGER", "ANY", 1); + public void onVillagerTrade(InventoryClickEvent event) { + if (!(event.getWhoClicked() instanceof Player player)) return; + if (event.getSlotType() != InventoryType.SlotType.RESULT) return; + if (event.getCurrentItem() == null || event.getCurrentItem().getType() == Material.AIR) return; + + if (event.getInventory().getHolder() instanceof Villager villager) { + String profession = getProfessionName(villager); + if (profession.equals("NONE")) profession = "VILLAGER"; + + plugin.getMissionManager().progressMission(player, "TRADE_VILLAGER", profession, 1); } } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onEnchantItem(EnchantItemEvent event) { - plugin.getMissionManager().progressMission(event.getEnchanter(), "ENCHANT_ITEM", "ANY", 1); + Player player = event.getEnchanter(); + ItemStack item = event.getItem(); + + if (item.getType() != Material.AIR) { + String itemType = item.getType().name(); + plugin.getMissionManager().progressMission(player, "ENCHANT_ITEM", itemType, 1); + } } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onPlayerFish(PlayerFishEvent event) { if (event.getState() == PlayerFishEvent.State.CAUGHT_FISH && event.getCaught() != null) { Player player = event.getPlayer(); - if (event.getCaught() instanceof org.bukkit.entity.Item) { - org.bukkit.entity.Item item = (org.bukkit.entity.Item) event.getCaught(); + if (event.getCaught() instanceof org.bukkit.entity.Item item) { String itemType = item.getItemStack().getType().name(); plugin.getMissionManager().progressMission(player, "FISH_ITEM", itemType, 1); } @@ -164,9 +221,8 @@ public void onPlayerFish(PlayerFishEvent event) { @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onCraftItem(CraftItemEvent event) { - if (!(event.getWhoClicked() instanceof Player)) return; + if (!(event.getWhoClicked() instanceof Player player)) return; - Player player = (Player) event.getWhoClicked(); ItemStack result = event.getRecipe().getResult(); if (result == null || result.getType() == Material.AIR) return; @@ -200,11 +256,7 @@ public void onBlockPlace(BlockPlaceEvent event) { Location blockLoc = event.getBlock().getLocation(); UUID uuid = player.getUniqueId(); - Map playerPlacedBlocks = recentlyPlacedBlocks.get(uuid); - if (playerPlacedBlocks == null) { - playerPlacedBlocks = new HashMap<>(); - recentlyPlacedBlocks.put(uuid, playerPlacedBlocks); - } + Map playerPlacedBlocks = recentlyPlacedBlocks.computeIfAbsent(uuid, k -> new HashMap<>()); Long lastPlaced = playerPlacedBlocks.get(blockLoc); long currentTime = System.currentTimeMillis(); @@ -277,6 +329,89 @@ public void onPlayerShearEntity(PlayerShearEntityEvent event) { } } + public String getProfessionName(Villager villager) { + Villager.Profession profession = villager.getProfession(); + + try { + // Old method + return profession.name(); + } catch (Exception e) { + // New method ('name()' is deprecated since version 1.21 and marked for removal) + // profession.key().value().replace("minecraft:", "").toUpperCase(); + try { + Method keyMethod = profession.getClass().getMethod("key"); + Object namespacedKey = keyMethod.invoke(profession); + Method valueMethod = namespacedKey.getClass().getMethod("value"); + String keyValue = (String) valueMethod.invoke(namespacedKey); + return keyValue.replace("minecraft:", "").toUpperCase(); + } catch (Exception ex) { + return "UNKNOWN"; + } + } + } + + private List enumerateDamageTypes(EntityDamageEvent event) { + List result = new ArrayList<>(); + + if (event instanceof EntityDamageByEntityEvent edbe) { + Entity rawDamager = edbe.getDamager(); + + if (rawDamager instanceof Projectile projectile) { + result.add(safeName(projectile.getType().name())); + + ProjectileSource shooter = projectile.getShooter(); + if (shooter instanceof Entity shooterEntity) { + if (shooterEntity instanceof Player) { + result.add("PLAYER"); + } else if (shooterEntity instanceof LivingEntity livingShooter) { + String mobBase = safeName(livingShooter.getType().name()); + result.add(mobBase); + } else { + result.add(safeName(shooterEntity.getType().name())); + } + } + } else { + if (rawDamager instanceof Player) { + result.add("PLAYER"); + } else if (rawDamager instanceof LivingEntity living) { + result.add(safeName(living.getType().name())); + } else { + result.add(safeName(rawDamager.getType().name())); + } + } + } + + result.add(safeName(getCauseName(event.getCause()))); + + return new ArrayList<>(new LinkedHashSet<>(result)); + } + + private Entity getTrueDamager(Entity damager) { + if (damager instanceof Projectile projectile) { + ProjectileSource ps = projectile.getShooter(); + if (ps instanceof Entity shooterEntity) return shooterEntity; + } + return damager; + } + + private String getCauseName(EntityDamageEvent.DamageCause cause) { + switch (cause) { + case FIRE, FIRE_TICK -> { + return "FIRE"; + } + case BLOCK_EXPLOSION, ENTITY_EXPLOSION -> { + return "EXPLOSION"; + } + default -> { + return cause.name(); + } + } + } + + private String safeName(String s) { + return s == null ? "UNKNOWN" : s.replaceAll("[^A-Z0-9_]", "_").toUpperCase(); + } + public void initializePlayerLocation(UUID uuid, Location location) { lastLocations.put(uuid, location); recentlyPlacedBlocks.put(uuid, new HashMap<>()); @@ -284,6 +419,7 @@ public void initializePlayerLocation(UUID uuid, Location location) { public void cleanupPlayer(UUID uuid) { lastLocations.remove(uuid); + distanceBuffer.remove(uuid); recentlyPlacedBlocks.remove(uuid); } } \ No newline at end of file diff --git a/src/main/java/com/Lino/battlePass/listeners/PlayerConnectionListener.java b/src/main/java/com/Lino/battlePass/listeners/PlayerConnectionListener.java index 2dd55aa..933ae7f 100644 --- a/src/main/java/com/Lino/battlePass/listeners/PlayerConnectionListener.java +++ b/src/main/java/com/Lino/battlePass/listeners/PlayerConnectionListener.java @@ -11,7 +11,6 @@ import org.bukkit.event.player.PlayerQuitEvent; import org.bukkit.scheduler.BukkitRunnable; -import java.util.HashMap; import java.util.Map; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; @@ -45,7 +44,7 @@ public void run() { PlayerData data = plugin.getPlayerDataManager().getPlayerData(uuid); if (data != null) { - int available = plugin.getRewardManager().countAvailableRewards(player, data); + int available = plugin.getRewardManager().countAvailableRewards(data); if (available > 0) { player.sendMessage(plugin.getMessageManager().getPrefix() + plugin.getMessageManager().getMessage("messages.rewards-available", diff --git a/src/main/java/com/Lino/battlePass/managers/DatabaseManager.java b/src/main/java/com/Lino/battlePass/managers/DatabaseManager.java index 318231b..2b5ba55 100644 --- a/src/main/java/com/Lino/battlePass/managers/DatabaseManager.java +++ b/src/main/java/com/Lino/battlePass/managers/DatabaseManager.java @@ -170,13 +170,22 @@ private void createTables() throws SQLException { "name TEXT," + "type TEXT," + "target TEXT," + + "additional_targets TEXT," + "required INTEGER," + "xp_reward INTEGER," + "date TEXT)" ); if (!isMySQL) { - stmt.executeUpdate("CREATE INDEX IF NOT EXISTS idx_missions_uuid_date ON " + prefix + "missions(uuid, date)"); + try { + stmt.executeUpdate("ALTER TABLE " + prefix + "daily_missions ADD COLUMN additional_targets TEXT"); + } catch (SQLException ignored) { + } + } else { + try { + stmt.executeUpdate("ALTER TABLE " + prefix + "daily_missions ADD COLUMN additional_targets TEXT DEFAULT ''"); + } catch (SQLException ignored) { + } } } } finally { @@ -567,8 +576,8 @@ public CompletableFuture saveDailyMissions(List missions, String if (missions.isEmpty()) return; String insertSql = isMySQL - ? "INSERT INTO " + prefix + "daily_missions (name, type, target, required, xp_reward, date) VALUES (?, ?, ?, ?, ?, ?) ON DUPLICATE KEY UPDATE name=VALUES(name)" - : "INSERT OR REPLACE INTO " + prefix + "daily_missions (name, type, target, required, xp_reward, date) VALUES (?, ?, ?, ?, ?, ?)"; + ? "INSERT INTO " + prefix + "daily_missions (name, type, target, additional_targets, required, xp_reward, date) VALUES (?, ?, ?, ?, ?, ?, ?) ON DUPLICATE KEY UPDATE name=VALUES(name), type=VALUES(type), target=VALUES(target), additional_targets=VALUES(additional_targets), required=VALUES(required), xp_reward=VALUES(xp_reward)" + : "INSERT OR REPLACE INTO " + prefix + "daily_missions (name, type, target, additional_targets, required, xp_reward, date) VALUES (?, ?, ?, ?, ?, ?, ?)"; Connection conn = null; boolean shouldClose = isMySQL; @@ -584,9 +593,10 @@ public CompletableFuture saveDailyMissions(List missions, String ps.setString(1, mission.name); ps.setString(2, mission.type); ps.setString(3, mission.target); - ps.setInt(4, mission.required); - ps.setInt(5, mission.xpReward); - ps.setString(6, missionDate); + ps.setString(4, String.join(",", mission.additionalTargets)); + ps.setInt(5, mission.required); + ps.setInt(6, mission.xpReward); + ps.setString(7, missionDate); ps.addBatch(); } ps.executeBatch(); @@ -616,10 +626,17 @@ public CompletableFuture> loadDailyMissions() { ps.setString(1, missionDate); try (ResultSet rs = ps.executeQuery()) { while (rs.next()) { + String additionalTargetsStr = rs.getString("additional_targets"); + List additionalTargets = new ArrayList<>(); + if (additionalTargetsStr != null && !additionalTargetsStr.isEmpty()) { + additionalTargets = Arrays.asList(additionalTargetsStr.split(",")); + } + loadedMissions.add(new Mission( rs.getString("name"), rs.getString("type"), rs.getString("target"), + additionalTargets, rs.getInt("required"), rs.getInt("xp_reward") )); diff --git a/src/main/java/com/Lino/battlePass/managers/GuiManager.java b/src/main/java/com/Lino/battlePass/managers/GuiManager.java index bfeebfd..493efd4 100644 --- a/src/main/java/com/Lino/battlePass/managers/GuiManager.java +++ b/src/main/java/com/Lino/battlePass/managers/GuiManager.java @@ -31,8 +31,7 @@ public GuiManager(BattlePass plugin, PlayerDataManager playerDataManager, Missio public void openBattlePassGUI(Player player, int page) { if (page < 1) page = 1; - int maxLevel = rewardManager.getMaxLevel(); - int maxPages = (int) Math.ceil(maxLevel / 9.0); + int maxPages = plugin.getRewardManager().getMaxPage(); if (maxPages < 1) maxPages = 1; if (page > maxPages) page = maxPages; diff --git a/src/main/java/com/Lino/battlePass/managers/MissionEditorManager.java b/src/main/java/com/Lino/battlePass/managers/MissionEditorManager.java index 9d8aa50..0118a2c 100644 --- a/src/main/java/com/Lino/battlePass/managers/MissionEditorManager.java +++ b/src/main/java/com/Lino/battlePass/managers/MissionEditorManager.java @@ -203,19 +203,10 @@ private String getDefaultTarget(String type) { } public boolean isTargetRequired(String type) { - switch (type) { - case "WALK_DISTANCE": - case "PLAY_TIME": - case "GAIN_XP": - case "DAMAGE_DEALT": - case "DAMAGE_TAKEN": - case "DEATH": - case "TRADE_VILLAGER": - case "ENCHANT_ITEM": - return false; - default: - return true; - } + return switch (type) { + case "PLAY_TIME", "GAIN_XP" -> false; + default -> true; + }; } public boolean isEditing(UUID uuid) { diff --git a/src/main/java/com/Lino/battlePass/managers/MissionGenerator.java b/src/main/java/com/Lino/battlePass/managers/MissionGenerator.java index d01eeb2..8f9eb0a 100644 --- a/src/main/java/com/Lino/battlePass/managers/MissionGenerator.java +++ b/src/main/java/com/Lino/battlePass/managers/MissionGenerator.java @@ -3,7 +3,6 @@ import com.Lino.battlePass.models.Mission; import com.Lino.battlePass.models.MissionTemplate; import org.bukkit.configuration.ConfigurationSection; -import org.bukkit.configuration.file.FileConfiguration; import java.util.*; import java.util.concurrent.ThreadLocalRandom; @@ -16,7 +15,7 @@ public MissionGenerator(ConfigManager configManager) { this.configManager = configManager; } - public List generateDailyMissions(String missionDate) { + public List generateDailyMissions() { ConfigurationSection pools = configManager.getMissionsConfig().getConfigurationSection("mission-pools"); if (pools == null) { return new ArrayList<>(); @@ -24,7 +23,6 @@ public List generateDailyMissions(String missionDate) { List newMissions = new ArrayList<>(); List weightedTemplates = new ArrayList<>(); - Map uniqueTemplates = new HashMap<>(); for (String key : pools.getKeys(false)) { ConfigurationSection missionSection = pools.getConfigurationSection(key); @@ -32,6 +30,7 @@ public List generateDailyMissions(String missionDate) { String type = missionSection.getString("type"); String target = missionSection.getString("target"); + List additionalTargets = missionSection.getStringList("additional-targets"); String displayName = missionSection.getString("display-name"); int minRequired = missionSection.getInt("min-required"); int maxRequired = missionSection.getInt("max-required"); @@ -39,15 +38,12 @@ public List generateDailyMissions(String missionDate) { int maxXP = missionSection.getInt("max-xp"); int weight = missionSection.getInt("weight", 10); - MissionTemplate template = new MissionTemplate(displayName, type, target, + MissionTemplate template = new MissionTemplate(displayName, type, target, additionalTargets, minRequired, maxRequired, minXP, maxXP); - - uniqueTemplates.put(key, template); weightedTemplates.add(new WeightedMissionTemplate(template, weight, key)); } int missionsToGenerate = configManager.getDailyMissionsCount(); - Set usedMissionKeys = new HashSet<>(); for (int i = 0; i < missionsToGenerate && !weightedTemplates.isEmpty(); i++) { WeightedMissionTemplate selected = selectWeightedRandom(weightedTemplates); @@ -55,7 +51,6 @@ public List generateDailyMissions(String missionDate) { if (selected != null) { Mission mission = createMissionFromTemplate(selected.template); newMissions.add(mission); - usedMissionKeys.add(selected.key); weightedTemplates.removeIf(w -> w.key.equals(selected.key)); } @@ -96,7 +91,7 @@ private Mission createMissionFromTemplate(MissionTemplate template) { .replace("", String.valueOf(required)) .replace("", formatTarget(template.target)); - return new Mission(name, template.type, template.target, required, xpReward); + return new Mission(name, template.type, template.target, template.additionalTargets, required, xpReward); } private String formatTarget(String target) { diff --git a/src/main/java/com/Lino/battlePass/managers/MissionManager.java b/src/main/java/com/Lino/battlePass/managers/MissionManager.java index 776235a..80de461 100644 --- a/src/main/java/com/Lino/battlePass/managers/MissionManager.java +++ b/src/main/java/com/Lino/battlePass/managers/MissionManager.java @@ -10,7 +10,7 @@ import java.time.LocalDateTime; import java.util.*; -import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CompletableFuture; public class MissionManager { @@ -82,7 +82,7 @@ private void loadMissionsAfterSeasonData() { if (resetHandler.getNextMissionReset() != null && now.isAfter(resetHandler.getNextMissionReset())) { currentMissionDate = now.toLocalDate().toString(); databaseManager.clearOldMissionProgress(currentMissionDate); - progressTracker.resetProgress(currentMissionDate); + progressTracker.resetProgress(); } generateDailyMissions(); @@ -110,7 +110,7 @@ private void generateDailyMissions() { currentMissionDate = LocalDateTime.now().toLocalDate().toString(); } - dailyMissions = new ArrayList<>(missionGenerator.generateDailyMissions(currentMissionDate)); + dailyMissions = new ArrayList<>(missionGenerator.generateDailyMissions()); } public void checkMissionReset() { @@ -127,7 +127,7 @@ public void checkMissionReset() { player.sendMessage(messageManager.getPrefix() + messageManager.getMessage("messages.mission.reset")); } - progressTracker.resetProgress(currentMissionDate); + progressTracker.resetProgress(); databaseManager.clearOldMissionProgress(currentMissionDate); } } @@ -144,7 +144,7 @@ private void resetSeason() { generateDailyMissions(); resetHandler.calculateNextReset(); saveSeasonData(); - progressTracker.resetProgress(currentMissionDate); + progressTracker.resetProgress(); } public void forceResetSeason() { @@ -153,7 +153,7 @@ public void forceResetSeason() { generateDailyMissions(); saveDailyMissions(); saveSeasonData(); - progressTracker.resetProgress(currentMissionDate); + progressTracker.resetProgress(); Bukkit.getScheduler().runTaskLater(plugin, () -> { if (plugin.getCoinsDistributionTask() != null) { @@ -180,8 +180,8 @@ public void forceResetMissions() { player.playSound(player.getLocation(), Sound.ENTITY_EXPERIENCE_ORB_PICKUP, 1.0f, 1.0f); } - progressTracker.resetProgress(currentMissionDate); - databaseManager.clearOldMissionProgress(currentMissionDate); + progressTracker.resetProgress(); + databaseManager.clearOldMissionProgress(LocalDateTime.now().plusDays(1).toLocalDate().toString()); } public void progressMission(Player player, String type, String target, int amount) { diff --git a/src/main/java/com/Lino/battlePass/managers/MissionProgressTracker.java b/src/main/java/com/Lino/battlePass/managers/MissionProgressTracker.java index e4d8358..c7136f1 100644 --- a/src/main/java/com/Lino/battlePass/managers/MissionProgressTracker.java +++ b/src/main/java/com/Lino/battlePass/managers/MissionProgressTracker.java @@ -37,7 +37,7 @@ public void trackProgress(Player player, String type, String target, int amount, for (Mission mission : dailyMissions) { if (!mission.type.equals(type)) continue; - if (!mission.target.equals("ANY") && !mission.target.equals(target)) continue; + if (!mission.isValidTarget(target)) continue; String missionKey = generateMissionKey(mission); @@ -83,7 +83,7 @@ private String generateMissionKey(Mission mission) { return mission.type + "_" + mission.target + "_" + mission.required + "_" + mission.name.hashCode(); } - public void resetProgress(String currentMissionDate) { + public void resetProgress() { playerCompletedMissions.clear(); lastActionbarUpdate.clear(); @@ -116,7 +116,7 @@ private void checkLevelUp(Player player, PlayerData data) { "%level%", String.valueOf(data.level))); player.playSound(player.getLocation(), Sound.UI_TOAST_CHALLENGE_COMPLETE, 1.0f, 1.0f); - int available = plugin.getRewardManager().countAvailableRewards(player, data); + int available = plugin.getRewardManager().countAvailableRewards(data); if (available > 0) { player.sendMessage(messageManager.getPrefix() + messageManager.getMessage("messages.new-rewards")); } diff --git a/src/main/java/com/Lino/battlePass/managers/RewardManager.java b/src/main/java/com/Lino/battlePass/managers/RewardManager.java index 3e34a00..9033d45 100644 --- a/src/main/java/com/Lino/battlePass/managers/RewardManager.java +++ b/src/main/java/com/Lino/battlePass/managers/RewardManager.java @@ -22,8 +22,6 @@ public class RewardManager { private final BattlePass plugin; private final ConfigManager configManager; - private final List freeRewards = new ArrayList<>(); - private final List premiumRewards = new ArrayList<>(); private final Map> freeRewardsByLevel = new HashMap<>(); private final Map> premiumRewardsByLevel = new HashMap<>(); @@ -36,8 +34,6 @@ public RewardManager(BattlePass plugin, ConfigManager configManager) { } public void loadRewards() { - freeRewards.clear(); - premiumRewards.clear(); freeRewardsByLevel.clear(); premiumRewardsByLevel.clear(); @@ -57,14 +53,12 @@ public void loadRewards() { if (freeConfig.contains(levelPath + ".material") || freeConfig.contains(levelPath + ".command")) { Reward reward = loadSingleReward(freeConfig, levelPath, i, true); if (reward != null) { - freeRewards.add(reward); freeLevel.add(reward); } } else if (freeConfig.contains(levelPath + ".items")) { for (String key : freeConfig.getConfigurationSection(levelPath + ".items").getKeys(false)) { Reward reward = loadSingleReward(freeConfig, levelPath + ".items." + key, i, true); if (reward != null) { - freeRewards.add(reward); freeLevel.add(reward); } } @@ -75,14 +69,12 @@ public void loadRewards() { if (premiumConfig.contains(levelPath + ".material") || premiumConfig.contains(levelPath + ".command")) { Reward reward = loadSingleReward(premiumConfig, levelPath, i, false); if (reward != null) { - premiumRewards.add(reward); premiumLevel.add(reward); } } else if (premiumConfig.contains(levelPath + ".items")) { for (String key : premiumConfig.getConfigurationSection(levelPath + ".items").getKeys(false)) { Reward reward = loadSingleReward(premiumConfig, levelPath + ".items." + key, i, false); if (reward != null) { - premiumRewards.add(reward); premiumLevel.add(reward); } } @@ -103,7 +95,8 @@ private void updateMaxLevel(FileConfiguration config) { if (level > maxLevel) { maxLevel = level; } - } catch (NumberFormatException ignored) {} + } catch (NumberFormatException ignored) { + } } } } @@ -235,7 +228,7 @@ public void claimRewards(Player player, PlayerData data, List rewards, plugin.getPlayerDataManager().markForSave(player.getUniqueId()); } - public int countAvailableRewards(Player player, PlayerData data) { + public int countAvailableRewards(PlayerData data) { int count = 0; for (int level : freeRewardsByLevel.keySet()) { if (data.level >= level && !data.claimedFreeRewards.contains(level)) { @@ -270,6 +263,10 @@ public int getMaxLevel() { return maxLevel; } + public int getMaxPage() { + return (int) Math.ceil(getMaxLevel() / 9.0); + } + public List getEditableRewards(int level, boolean isPremium) { List editableRewards = new ArrayList<>(); FileConfiguration config = isPremium ? diff --git a/src/main/java/com/Lino/battlePass/managers/ShopManager.java b/src/main/java/com/Lino/battlePass/managers/ShopManager.java index 494b7b9..40cf9a0 100644 --- a/src/main/java/com/Lino/battlePass/managers/ShopManager.java +++ b/src/main/java/com/Lino/battlePass/managers/ShopManager.java @@ -20,7 +20,6 @@ public class ShopManager { private final BattlePass plugin; - private FileConfiguration shopConfig; private final Map shopItems = new HashMap<>(); public ShopManager(BattlePass plugin) { @@ -34,7 +33,7 @@ public void loadShop() { plugin.saveResource("shop.yml", false); } - shopConfig = YamlConfiguration.loadConfiguration(shopFile); + FileConfiguration shopConfig = YamlConfiguration.loadConfiguration(shopFile); shopItems.clear(); ConfigurationSection items = shopConfig.getConfigurationSection("shop-items"); diff --git a/src/main/java/com/Lino/battlePass/models/Mission.java b/src/main/java/com/Lino/battlePass/models/Mission.java index 6c91633..d8fb10d 100644 --- a/src/main/java/com/Lino/battlePass/models/Mission.java +++ b/src/main/java/com/Lino/battlePass/models/Mission.java @@ -1,17 +1,29 @@ package com.Lino.battlePass.models; +import java.util.List; +import java.util.ArrayList; + public class Mission { public final String name; public final String type; public final String target; + public final List additionalTargets; public final int required; public final int xpReward; - public Mission(String name, String type, String target, int required, int xpReward) { + public Mission(String name, String type, String target, List additionalTargets, int required, int xpReward) { this.name = name; this.type = type; this.target = target; + this.additionalTargets = additionalTargets != null ? additionalTargets : new ArrayList<>(); this.required = required; this.xpReward = xpReward; } + + public boolean isValidTarget(String actionTarget) { + if ("ANY".equals(target) || target.equalsIgnoreCase(actionTarget)) { + return true; + } + return additionalTargets.stream().anyMatch(additional -> additional.equalsIgnoreCase(actionTarget)); + } } \ No newline at end of file diff --git a/src/main/java/com/Lino/battlePass/models/MissionTemplate.java b/src/main/java/com/Lino/battlePass/models/MissionTemplate.java index 2626cb6..e595984 100644 --- a/src/main/java/com/Lino/battlePass/models/MissionTemplate.java +++ b/src/main/java/com/Lino/battlePass/models/MissionTemplate.java @@ -1,19 +1,24 @@ package com.Lino.battlePass.models; +import java.util.List; +import java.util.ArrayList; + public class MissionTemplate { public final String nameFormat; public final String type; public final String target; + public final List additionalTargets; public final int minRequired; public final int maxRequired; public final int minXP; public final int maxXP; - public MissionTemplate(String nameFormat, String type, String target, int minRequired, - int maxRequired, int minXP, int maxXP) { + public MissionTemplate(String nameFormat, String type, String target, List additionalTargets, + int minRequired, int maxRequired, int minXP, int maxXP) { this.nameFormat = nameFormat; this.type = type; this.target = target; + this.additionalTargets = additionalTargets != null ? additionalTargets : new ArrayList<>(); this.minRequired = minRequired; this.maxRequired = maxRequired; this.minXP = minXP; diff --git a/src/main/java/com/Lino/battlePass/placeholders/BattlePassExpansion.java b/src/main/java/com/Lino/battlePass/placeholders/BattlePassExpansion.java index 2d15ad7..b5c4456 100644 --- a/src/main/java/com/Lino/battlePass/placeholders/BattlePassExpansion.java +++ b/src/main/java/com/Lino/battlePass/placeholders/BattlePassExpansion.java @@ -91,7 +91,7 @@ public String onRequest(OfflinePlayer player, String identifier) { case "available_rewards": if (player.isOnline()) { Player onlinePlayer = player.getPlayer(); - return String.valueOf(plugin.getRewardManager().countAvailableRewards(onlinePlayer, data)); + return String.valueOf(plugin.getRewardManager().countAvailableRewards(data)); } return "0"; diff --git a/src/main/java/com/Lino/battlePass/tasks/BattlePassTask.java b/src/main/java/com/Lino/battlePass/tasks/BattlePassTask.java index ac22845..538859b 100644 --- a/src/main/java/com/Lino/battlePass/tasks/BattlePassTask.java +++ b/src/main/java/com/Lino/battlePass/tasks/BattlePassTask.java @@ -44,7 +44,7 @@ private void checkRewardNotifications() { PlayerData data = plugin.getPlayerDataManager().getPlayerData(player.getUniqueId()); if (data == null) continue; - int availableRewards = plugin.getRewardManager().countAvailableRewards(player, data); + int availableRewards = plugin.getRewardManager().countAvailableRewards(data); if (availableRewards > data.lastNotification) { player.sendMessage(plugin.getMessageManager().getPrefix() + diff --git a/src/main/resources/messages.yml b/src/main/resources/messages.yml index 739933f..36ee36a 100644 --- a/src/main/resources/messages.yml +++ b/src/main/resources/messages.yml @@ -128,7 +128,7 @@ items: name: "⭐ Your Progress" lore: - "&7" - - "&8▸ &7Level: %level%&7/54" + - "&8▸ &7Level: %level%&7/%max_level%" - "&8▸ &7XP: %xp%&7/%xp_needed%" - "&7" - "&8▸ &7Premium Pass: %premium_status%" diff --git a/src/main/resources/missions.yml b/src/main/resources/missions.yml index 452244b..775219e 100644 --- a/src/main/resources/missions.yml +++ b/src/main/resources/missions.yml @@ -5,6 +5,10 @@ mission-pools: kill-zombies: type: KILL_MOB target: ZOMBIE + additional-targets: + - ZOMBIE_VILLAGER + - DROWNED + - HUSK display-name: "Kill Zombies" min-required: 15 max-required: 40 @@ -15,6 +19,9 @@ mission-pools: kill-skeletons: type: KILL_MOB target: SKELETON + additional-targets: + - STRAY + - BOGGED display-name: "Kill Skeletons" min-required: 15 max-required: 35 @@ -25,6 +32,8 @@ mission-pools: kill-spiders: type: KILL_MOB target: SPIDER + additional-targets: + - CAVE_SPIDER display-name: "Kill Spiders" min-required: 10 max-required: 30 @@ -97,6 +106,8 @@ mission-pools: mine-coal: type: MINE_BLOCK target: COAL_ORE + additional-targets: + - DEEPSLATE_COAL_ORE display-name: "Mine Coal Ores" min-required: 30 max-required: 100 @@ -107,6 +118,8 @@ mission-pools: mine-iron: type: MINE_BLOCK target: IRON_ORE + additional-targets: + - DEEPSLATE_IRON_ORE display-name: "Mine Iron Ores" min-required: 20 max-required: 60 @@ -117,6 +130,8 @@ mission-pools: mine-gold: type: MINE_BLOCK target: GOLD_ORE + additional-targets: + - DEEPSLATE_GOLD_ORE display-name: "Mine Gold Ores" min-required: 10 max-required: 30 @@ -127,26 +142,20 @@ mission-pools: mine-diamonds: type: MINE_BLOCK target: DIAMOND_ORE + additional-targets: + - DEEPSLATE_DIAMOND_ORE display-name: "Mine Diamond Ores" min-required: 5 max-required: 15 - min-xp: 400 - max-xp: 600 - weight: 6 - - mine-deepslate-diamonds: - type: MINE_BLOCK - target: DEEPSLATE_DIAMOND_ORE - display-name: "Mine Deepslate Diamonds" - min-required: 5 - max-required: 15 - min-xp: 450 - max-xp: 650 + min-xp: 425 + max-xp: 625 weight: 6 mine-lapis: type: MINE_BLOCK target: LAPIS_ORE + additional-targets: + - DEEPSLATE_LAPIS_ORE display-name: "Mine Lapis Ores" min-required: 15 max-required: 40 @@ -157,6 +166,8 @@ mission-pools: mine-redstone: type: MINE_BLOCK target: REDSTONE_ORE + additional-targets: + - DEEPSLATE_REDSTONE_ORE display-name: "Mine Redstone Ores" min-required: 20 max-required: 50 @@ -188,6 +199,10 @@ mission-pools: break-logs: type: BREAK_BLOCK target: OAK_LOG + additional-targets: + - STRIPPED_OAK_LOG + - OAK_WOOD + - STRIPPED_OAK_WOOD display-name: "Chop Oak Logs" min-required: 64 max-required: 200 @@ -205,6 +220,24 @@ mission-pools: max-xp: 200 weight: 9 + break-dirt: + type: BREAK_BLOCK + target: DIRT + additional-targets: + - GRASS_BLOCK + - COARSE_DIRT + - ROOTED_DIRT + - PODZOL + - MYCELIUM + - DIRT_PATH + - FARMLAND + display-name: "Break Dirt" + min-required: 200 + max-required: 500 + min-xp: 80 + max-xp: 160 + weight: 9 + eat-bread: type: EAT_ITEM target: BREAD @@ -235,6 +268,29 @@ mission-pools: max-xp: 800 weight: 4 + # Place blocks + place-wood: + type: PLACE_BLOCK + target: OAK_PLANKS + additional-targets: + - SPRUCE_PLANKS + - BIRCH_PLANKS + - JUNGLE_PLANKS + - ACACIA_PLANKS + - DARK_OAK_PLANKS + - MANGROVE_PLANKS + - CHERRY_PLANKS + - BAMBOO_PLANKS + - CRIMSON_PLANKS + - WARPED_PLANKS + - PALE_OAK_PLANKS + display-name: "Place Planks" + min-required: 64 + max-required: 200 + min-xp: 80 + max-xp: 150 + weight: 9 + # Crafting & Smelting smelt-iron: type: SMELT_ITEM @@ -301,6 +357,8 @@ mission-pools: breed-cows: type: BREED_ANIMAL target: COW + additional-targets: + - MOOSHROOM display-name: "Breed Cows" min-required: 5 max-required: 20 @@ -338,53 +396,250 @@ mission-pools: max-xp: 500 weight: 5 - trade-villager: + # Trade missions + # Supported targets: ANY, FARMER, FISHERMAN, SHEPHERD, FLETCHER, LIBRARIAN, CARTOGRAPHER, + # CLERIC, ARMORER, WEAPONSMITH, TOOLSMITH, BUTCHER, LEATHERWORKER, MASON, MERCHANT + trade-agriculture: type: TRADE_VILLAGER - target: ANY - display-name: "Trade Times with Villagers" + target: FARMER + additional-targets: + - FISHERMAN + - SHEPHERD + - BUTCHER + display-name: "Trade with Agriculture Villagers Times" min-required: 5 max-required: 20 min-xp: 200 max-xp: 400 weight: 7 - enchant-items: + trade-crafters: + type: TRADE_VILLAGER + target: ARMORER + additional-targets: + - WEAPONSMITH + - TOOLSMITH + - FLETCHER + - LEATHERWORKER + - MASON + display-name: "Change with Crafters Villagers Times" + min-required: 5 + max-required: 20 + min-xp: 200 + max-xp: 400 + weight: 7 + + # Enchant missions + enchant-swords: type: ENCHANT_ITEM - target: ANY - display-name: "Enchant Items" + target: DIAMOND_SWORD + additional-targets: + - NETHERITE_SWORD + - IRON_SWORD + - GOLDEN_SWORD + - STONE_SWORD + - WOODEN_SWORD + display-name: "Enchant swords" min-required: 3 max-required: 10 min-xp: 250 max-xp: 500 weight: 6 - # General Progression - gain-xp: - type: GAIN_XP - target: ANY - display-name: "Gain XP Points" - min-required: 500 - max-required: 2000 + enchant-armor: + type: ENCHANT_ITEM + target: DIAMOND_CHESTPLATE + additional-targets: + - NETHERITE_HELMET + - NETHERITE_CHESTPLATE + - NETHERITE_LEGGINGS + - NETHERITE_BOOTS + - DIAMOND_HELMET + - DIAMOND_LEGGINGS + - DIAMOND_BOOTS + - IRON_HELMET + - IRON_CHESTPLATE + - IRON_LEGGINGS + - IRON_BOOTS + - GOLDEN_HELMET + - GOLDEN_CHESTPLATE + - GOLDEN_LEGGINGS + - GOLDEN_BOOTS + - LEATHER_HELMET + - LEATHER_CHESTPLATE + - LEATHER_LEGGINGS + - LEATHER_BOOTS + - CHAINMAIL_HELMET + - CHAINMAIL_CHESTPLATE + - CHAINMAIL_LEGGINGS + - CHAINMAIL_BOOTS + display-name: "Enchant armors" + min-required: 3 + max-required: 10 + min-xp: 250 + max-xp: 500 + weight: 6 + + # DamageDeal missions + # Supported targets: ANY, PLAYER, ANY MOBS + damage-sea-creatures: + type: DAMAGE_DEALT + target: GUARDIAN + additional-targets: + - ELDER_GUARDIAN + - SQUID + - GLOW_SQUID + - DOLPHIN + - TURTLE + - COD + - SALMON + - PUFFERFISH + - TROPICAL_FISH + - AXOLOTL + display-name: "Deal Damage to sea creatures" + min-required: 700 + max-required: 3500 min-xp: 200 max-xp: 400 + weight: 7 + + damage-nether-creatures: + type: DAMAGE_DEALT + target: ZOMBIFIED_PIGLIN + additional-targets: + - BLAZE + - GHAST + - MAGMA_CUBE + - WITHER_SKELETON + - PIGLIN + - PIGLIN_BRUTE + - HOGLIN + - ZOGLIN + - STRIDER + display-name: "Deal Damage to nether creatures" + min-required: 700 + max-required: 3500 + min-xp: 200 + max-xp: 400 + weight: 7 + + damage-end-creatures: + type: DAMAGE_DEALT + target: ENDERMAN + additional-targets: + - ENDERMITE + - SHULKER + - ENDER_DRAGON + display-name: "Deal Damage to end creatures" + min-required: 450 + max-required: 1500 + min-xp: 190 + max-xp: 370 + weight: 4 + + damage-overworld-animals: + type: DAMAGE_DEALT + target: COW + additional-targets: + - PIG + - SHEEP + - CHICKEN + - RABBIT + - FOX + - PANDA + - BEE + - POLAR_BEAR + - WOLF + - OCELOT + - CAT + - PARROT + - DONKEY + - HORSE + - MULE + - LLAMA + - TRADER_LLAMA + - GOAT + - FROG + - TADPOLE + display-name: "Deal Damage to overworld animals" + min-required: 500 + max-required: 2500 + min-xp: 160 + max-xp: 320 weight: 8 - walk-distance: + damage-flying-creatures: + type: DAMAGE_DEALT + target: GHAST + additional-targets: + - BLAZE + - PHANTOM + - BAT + - PARROT + - BEE + - ENDER_DRAGON + - WITHER + display-name: "Deal Damage to Flying creatures" + min-required: 250 + max-required: 1500 + min-xp: 190 + max-xp: 370 + weight: 4 + + #DamageTaken missions + # Supported targets: ANY, PLAYER, ANY MOBS, FIRE, LAVA, FALL, DROWNING, POISON, + # EXPLOSION, VOID, STARVATION, CONTACT + take-damage-fall: + type: DAMAGE_TAKEN + target: FALL + display-name: "Take Damage from fall" + min-required: 25 + max-required: 75 + min-xp: 100 + max-xp: 200 + weight: 9 + + take-damage-fire: + type: DAMAGE_TAKEN + target: FIRE + additional-targets: + - LAVA + display-name: "Take Damage from fire" + min-required: 50 + max-required: 150 + min-xp: 100 + max-xp: 200 + weight: 9 + + # WalkDistance missions + # Supported targets: ANY, WALK, SWIM, FLY, SHIFT + move-distance: type: WALK_DISTANCE target: ANY - display-name: "Walk Blocks" + display-name: "Move Blocks" min-required: 2000 max-required: 10000 min-xp: 150 max-xp: 300 weight: 9 - deal-damage: - type: DAMAGE_DEALT + swim-distance: + type: WALK_DISTANCE + target: SWIM + display-name: "Swim Blocks" + min-required: 1500 + max-required: 7500 + min-xp: 160 + max-xp: 320 + weight: 8 + + # General Progression + gain-xp: + type: GAIN_XP target: ANY - display-name: "Deal Damage" - min-required: 1000 - max-required: 5000 + display-name: "Gain XP Points" + min-required: 500 + max-required: 2000 min-xp: 200 max-xp: 400 weight: 8