From ccba5e3bd894fb0974183e254ec13f563a3e5a35 Mon Sep 17 00:00:00 2001 From: Torrie Fischer Date: Mon, 14 Jun 2021 13:30:04 -0700 Subject: [PATCH] src: swap out region charges for XP levels as fuel, implement a mode where posts malfunction if you dont have enough levels --- src/main/java/us/camin/regions/Region.java | 22 ++++++ .../regions/RegionPostInteractionWatcher.java | 4 +- .../regions/ui/PlayerInventoryTeleporter.java | 36 +++++++--- .../us/camin/regions/ui/PlayerTeleporter.java | 69 ++++++++++++++++++- 4 files changed, 118 insertions(+), 13 deletions(-) diff --git a/src/main/java/us/camin/regions/Region.java b/src/main/java/us/camin/regions/Region.java index 3f4b75b..d30042e 100644 --- a/src/main/java/us/camin/regions/Region.java +++ b/src/main/java/us/camin/regions/Region.java @@ -148,6 +148,28 @@ public class Region { m_charges += charges; } + public int getTravelCost(Region destination) { + int baseCost = getBaseTravelCost(destination); + if (destination.isHub()) { + // Travel *to* a hub is 50% cheaper, before charges applied + baseCost /= 2; + } + return Math.max(1, (int)(baseCost / (Math.min(4, m_charges + 1)))); + } + + public int getBaseTravelCost(Region destination) { + if (m_isHub && destination.isHub()) { + // Free travel between hubs + return 0; + } else if (m_isHub) { + // Max cost 1 level for travel *from* a hub + return 1; + } + double distance = teleportLocation().distance(destination.teleportLocation()); + double blocksPerXP = 500; + return Math.max(1, (int)(distance / blocksPerXP)); + } + int m_visits = 0; int m_charges = 0; diff --git a/src/main/java/us/camin/regions/RegionPostInteractionWatcher.java b/src/main/java/us/camin/regions/RegionPostInteractionWatcher.java index 544d9f5..ecb0053 100644 --- a/src/main/java/us/camin/regions/RegionPostInteractionWatcher.java +++ b/src/main/java/us/camin/regions/RegionPostInteractionWatcher.java @@ -128,10 +128,8 @@ public class RegionPostInteractionWatcher implements Listener { RegionPostBuilder builder = new RegionPostBuilder(nearest, m_plugin); builder.build(); }); - } else if (nearest.charges() > 0 || player.hasPermission("regions.bypass.charges")) { - m_plugin.getServer().getPluginManager().callEvent(new PlayerPostInteractEvent(player, nearest)); } else { - player.sendMessage("This region post is not charged. Right click on it while sneaking and holding a Region Post Charge."); + m_plugin.getServer().getPluginManager().callEvent(new PlayerPostInteractEvent(player, nearest)); } } } diff --git a/src/main/java/us/camin/regions/ui/PlayerInventoryTeleporter.java b/src/main/java/us/camin/regions/ui/PlayerInventoryTeleporter.java index 6f7357d..e94cd0c 100644 --- a/src/main/java/us/camin/regions/ui/PlayerInventoryTeleporter.java +++ b/src/main/java/us/camin/regions/ui/PlayerInventoryTeleporter.java @@ -22,6 +22,7 @@ import java.util.Map; import java.util.HashMap; import java.util.ArrayList; import java.util.Optional; +import java.util.Random; import org.bukkit.event.Listener; import org.bukkit.event.EventHandler; import org.bukkit.ChatColor; @@ -29,7 +30,10 @@ import org.bukkit.event.Event.Result; import org.bukkit.DyeColor; import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.Sound; +import org.bukkit.Particle; import org.bukkit.entity.Player; +import org.bukkit.block.BlockFace; +import org.bukkit.block.Block; import org.bukkit.Location; import org.bukkit.inventory.Inventory; import org.bukkit.inventory.ItemStack; @@ -40,6 +44,7 @@ import org.bukkit.enchantments.Enchantment; import org.bukkit.inventory.ItemFlag; import org.bukkit.Material; import org.bukkit.material.MaterialData; +import org.bukkit.util.Vector; import us.camin.regions.Plugin; import us.camin.regions.Region; @@ -99,22 +104,25 @@ public class PlayerInventoryTeleporter implements Listener { .filter((r) -> r.name().equals(selectedName)) .findFirst(); if (destination.isPresent()) { - player.sendMessage("Teleporting you there now..."); - nearest.addCharges(-1); - destination.get().addCharges(1); + Location targetLocation = destination.get().teleportLocation(); + int cost = nearest.getTravelCost(destination.get()); + int chargesConsumed = Math.min(nearest.charges(), (int)cost - player.getLevel()); + double payment = player.getLevel() + chargesConsumed; + double accuracy = 0.8 + (payment / cost) * 0.2; + if (chargesConsumed > 0) { + nearest.addCharges(-chargesConsumed); + player.sendMessage("You don't have enough XP. "+ chargesConsumed + " charges were consumed."); + } + player.giveExpLevels(-(int)cost); m_plugin.getServer().getScheduler().runTask(m_plugin, () -> { RegionPostBuilder builder = new RegionPostBuilder(nearest, m_plugin); builder.updateLantern(); }); m_plugin.saveRegions(); - new PlayerTeleporter(player, nearest.teleportLocation(), destination.get().teleportLocation(), m_plugin).teleport().thenRun(() -> { + new PlayerTeleporter(player, nearest.teleportLocation(), targetLocation, m_plugin, accuracy).teleport().thenRun(() -> { RegionPostBuilder builder = new RegionPostBuilder(destination.get(), m_plugin); builder.updateLantern(); }); - if (nearest.charges() == 0) { - nearest.location().getWorld().playSound(player.getLocation(), Sound.ENTITY_ITEM_BREAK, (float)1.0, (float)1.0); - //player.sendMessage("You've consumed this region post's last charge! You won't be able to return without recharging it."); - } } else { player.sendMessage("There is no region with that name. This is a bug."); } @@ -169,6 +177,15 @@ public class PlayerInventoryTeleporter implements Listener { meta.addItemFlags(ItemFlag.HIDE_ENCHANTS); meta.addEnchant(Enchantment.SOUL_SPEED, 1, true); } + int cost = event.region.getTravelCost(region); + int baseCost = event.region.getBaseTravelCost(region); + if (cost != baseCost) { + lore.add(ChatColor.WHITE + "Travel cost: " + ChatColor.YELLOW + ChatColor.STRIKETHROUGH + Math.round(baseCost) + ChatColor.RESET + ChatColor.YELLOW + ChatColor.BOLD + " " + Math.round(cost) + " levels"); + } else if (cost > 0) { + lore.add(ChatColor.WHITE + "Travel cost: " + ChatColor.YELLOW + Math.round(cost) + " levels"); + } else { + lore.add(ChatColor.WHITE + "Travel cost: " + ChatColor.GREEN + "Free!"); + } lore.add(ChatColor.WHITE + "Distance: " + ChatColor.YELLOW + Math.round(region.location().distance(event.region.location()))); lore.add(ChatColor.WHITE + "Population: " + ChatColor.YELLOW + m_plugin.playerWatcher().playersInRegion(region).size()); lore.add(ChatColor.WHITE + "Altitude: " + ChatColor.YELLOW + altitude); @@ -180,6 +197,9 @@ public class PlayerInventoryTeleporter implements Listener { } } lore.add("Nearby connections: " + String.join(", ", neighborNames)); + if (event.player.getLevel() < cost) { + lore.add("" + ChatColor.RED + ChatColor.BOLD + "You don't have enough XP! Travel may be dangerous..."); + } } else { lore.add("" + ChatColor.BOLD + ChatColor.GOLD + "You haven't discovered this location yet!"); lore.add(ChatColor.WHITE + "Distance: " + ChatColor.YELLOW + ChatColor.MAGIC + Math.round(region.location().distance(event.region.location()))); diff --git a/src/main/java/us/camin/regions/ui/PlayerTeleporter.java b/src/main/java/us/camin/regions/ui/PlayerTeleporter.java index 0c5f720..1b07b6c 100644 --- a/src/main/java/us/camin/regions/ui/PlayerTeleporter.java +++ b/src/main/java/us/camin/regions/ui/PlayerTeleporter.java @@ -6,8 +6,12 @@ import org.bukkit.scheduler.BukkitTask; import org.bukkit.Particle; import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause; import org.bukkit.scheduler.BukkitScheduler; +import org.bukkit.ChatColor; import org.bukkit.World; import org.bukkit.Sound; +import org.bukkit.block.BlockFace; +import org.bukkit.block.Block; +import java.util.Random; import io.papermc.lib.PaperLib; import us.camin.regions.Plugin; @@ -15,6 +19,7 @@ import java.util.logging.Logger; import org.bukkit.potion.PotionEffectType; import org.bukkit.potion.PotionEffect; import java.util.concurrent.CompletableFuture; +import org.bukkit.util.Vector; public class PlayerTeleporter { Logger log = Logger.getLogger("Regions.PlayerTeleporter"); @@ -23,12 +28,30 @@ public class PlayerTeleporter { private Location m_src; private Location m_dest; private Plugin m_plugin; + private double m_accuracy; - public PlayerTeleporter(Player p, Location src, Location dest, Plugin plugin) { + public PlayerTeleporter(Player p, Location src, Location dest, Plugin plugin, double accuracy) { this.m_player = p; this.m_src = src; this.m_dest = dest; this.m_plugin = plugin; + this.m_accuracy = accuracy; + + if (m_accuracy < 1) { + Random rand = new Random(); + + Vector travelVec = m_dest.toVector().subtract(m_src.toVector()).normalize(); + double angleDelta = (Math.PI / 3) * (rand.nextGaussian() - 0.5) * (1-accuracy); + travelVec.rotateAroundY(angleDelta); + + double distanceToDest = m_src.distance(m_dest); + double distanceDelta = (distanceToDest/3) * (rand.nextGaussian() - 0.5) * (1 - accuracy); + double targetDistance = distanceToDest - distanceDelta; + + travelVec.multiply(targetDistance); + + m_dest = m_src.clone().add(travelVec); + } } public CompletableFuture teleport() { @@ -37,6 +60,22 @@ public class PlayerTeleporter { BukkitTask hoverGenerator = scheduler.runTaskTimer(m_plugin, () -> applyHoverEffect(), 0, 10); BukkitTask particleGenerator = scheduler.runTaskTimer(m_plugin, () -> spawnHoverParticles(), 0, 1); + BukkitTask noiseGenerator = scheduler.runTaskTimer(m_plugin, () -> { + if (m_accuracy < 1) { + m_player.getLocation().getWorld().playSound(m_player.getLocation(), Sound.ENTITY_GENERIC_EXPLODE, (float)0.5, (float)1.0); + m_player.getLocation().getWorld().spawnParticle(Particle.EXPLOSION_LARGE, m_player.getLocation(), 3, 1, 1, 1); + } + }, 20, 15); + + if (m_accuracy < 1) { + m_player.sendMessage("Teleporting you there-ish now..."); + m_plugin.getServer().getScheduler().runTaskLater(m_plugin, () -> { + m_player.sendMessage("" + ChatColor.RED + ChatColor.BOLD + "Oh no!" + ChatColor.RESET + ChatColor.YELLOW + " The region post is malfunctioning!"); + }, 40); + } else { + m_player.sendMessage("Teleporting you there now..."); + } + playTeleportSound(); m_plugin.getServer().getScheduler().runTaskLater(m_plugin, () -> { @@ -46,11 +85,23 @@ public class PlayerTeleporter { m_plugin.getServer().getScheduler().runTaskLater(m_plugin, () -> { spawnTeleportStartParticles(); PaperLib.teleportAsync(m_player, m_dest, TeleportCause.COMMAND).thenAccept(res -> { + Block targetBlock = m_dest.getBlock(); + if (!targetBlock.isPassable() && !targetBlock.getRelative(BlockFace.DOWN).isPassable()) { + while (!(targetBlock.isPassable() && targetBlock.getRelative(BlockFace.UP).isEmpty() && !targetBlock.getRelative(BlockFace.DOWN).isPassable())) { + targetBlock = targetBlock.getRelative(BlockFace.UP); + } + m_dest = targetBlock.getLocation().add(0.5, 0, 0.5); + m_player.teleport(m_dest, TeleportCause.COMMAND); + } m_player.addPotionEffect(new PotionEffect(PotionEffectType.BLINDNESS, 60, 1, false, false, false)); m_player.addPotionEffect(new PotionEffect(PotionEffectType.SLOW, 40, 1, false, false, false)); + if (m_accuracy < 1) { + m_player.addPotionEffect(new PotionEffect(PotionEffectType.SLOW_FALLING, 20 * 5, 1, false, true, false)); + } spawnEndParticles(); particleGenerator.cancel(); hoverGenerator.cancel(); + noiseGenerator.cancel(); ret.complete(null); }); }, 20 * 6); @@ -63,11 +114,22 @@ public class PlayerTeleporter { } void spawnEndParticles() { - World world = m_player.getLocation().getWorld(); + final World world = m_player.getLocation().getWorld(); world.playSound(m_dest, Sound.BLOCK_PORTAL_TRAVEL, (float)0.5, (float)1.0); world.spawnParticle(Particle.CLOUD, m_dest, 70, 1, 1, 1); world.spawnParticle(Particle.SPELL_MOB, m_dest, 5, 2, 2, 2); world.spawnParticle(Particle.PORTAL, m_player.getLocation(), 70, 1, 1, 1); + if (m_accuracy < 1) { + BukkitTask fireGenerator = m_plugin.getServer().getScheduler().runTaskTimer(m_plugin, () -> { + world.spawnParticle(Particle.FLAME, m_player.getLocation(), 80, 1, 1, 1, 0); + }, 0, 8); + m_plugin.getServer().getScheduler().runTaskLater(m_plugin, () -> { + fireGenerator.cancel(); + }, 20 * 8); + m_player.sendMessage("" + ChatColor.RED + ChatColor.BOLD + "Ouch!" + ChatColor.RESET + ChatColor.YELLOW + " You didn't have enough XP and the region post malfunctioned."); + m_player.damage(5 * (1.0-m_accuracy)); + world.playSound(m_player.getLocation(), Sound.ENTITY_GENERIC_EXPLODE, (float)1.0, (float)1.0); + } } void applyHoverEffect() { @@ -84,5 +146,8 @@ public class PlayerTeleporter { m_src.getWorld().playSound(m_src, Sound.BLOCK_PORTAL_TRIGGER, (float)0.5, (float)0.6); m_src.getWorld().playSound(m_src, Sound.BLOCK_RESPAWN_ANCHOR_DEPLETE, (float)0.5, (float)1.0); m_src.getWorld().playSound(m_dest, Sound.BLOCK_RESPAWN_ANCHOR_CHARGE, (float)0.5, (float)1.0); + if (m_accuracy < 1) { + m_src.getWorld().playSound(m_src, Sound.ENTITY_ITEM_BREAK, (float)1.0, (float)1.0); + } } }