src: swap out region charges for XP levels as fuel, implement a mode where posts malfunction if you dont have enough levels

This commit is contained in:
Torrie Fischer 2021-06-14 13:30:04 -07:00
parent d18c6e54f9
commit ccba5e3bd8
4 changed files with 118 additions and 13 deletions

View File

@ -148,6 +148,28 @@ public class Region {
m_charges += charges; 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_visits = 0;
int m_charges = 0; int m_charges = 0;

View File

@ -128,10 +128,8 @@ public class RegionPostInteractionWatcher implements Listener {
RegionPostBuilder builder = new RegionPostBuilder(nearest, m_plugin); RegionPostBuilder builder = new RegionPostBuilder(nearest, m_plugin);
builder.build(); builder.build();
}); });
} else if (nearest.charges() > 0 || player.hasPermission("regions.bypass.charges")) {
m_plugin.getServer().getPluginManager().callEvent(new PlayerPostInteractEvent(player, nearest));
} else { } 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));
} }
} }
} }

View File

@ -22,6 +22,7 @@ import java.util.Map;
import java.util.HashMap; import java.util.HashMap;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Optional; import java.util.Optional;
import java.util.Random;
import org.bukkit.event.Listener; import org.bukkit.event.Listener;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
import org.bukkit.ChatColor; import org.bukkit.ChatColor;
@ -29,7 +30,10 @@ import org.bukkit.event.Event.Result;
import org.bukkit.DyeColor; import org.bukkit.DyeColor;
import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.Sound; import org.bukkit.Sound;
import org.bukkit.Particle;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.block.BlockFace;
import org.bukkit.block.Block;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.inventory.Inventory; import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
@ -40,6 +44,7 @@ import org.bukkit.enchantments.Enchantment;
import org.bukkit.inventory.ItemFlag; import org.bukkit.inventory.ItemFlag;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.material.MaterialData; import org.bukkit.material.MaterialData;
import org.bukkit.util.Vector;
import us.camin.regions.Plugin; import us.camin.regions.Plugin;
import us.camin.regions.Region; import us.camin.regions.Region;
@ -99,22 +104,25 @@ public class PlayerInventoryTeleporter implements Listener {
.filter((r) -> r.name().equals(selectedName)) .filter((r) -> r.name().equals(selectedName))
.findFirst(); .findFirst();
if (destination.isPresent()) { if (destination.isPresent()) {
player.sendMessage("Teleporting you there now..."); Location targetLocation = destination.get().teleportLocation();
nearest.addCharges(-1); int cost = nearest.getTravelCost(destination.get());
destination.get().addCharges(1); 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, () -> { m_plugin.getServer().getScheduler().runTask(m_plugin, () -> {
RegionPostBuilder builder = new RegionPostBuilder(nearest, m_plugin); RegionPostBuilder builder = new RegionPostBuilder(nearest, m_plugin);
builder.updateLantern(); builder.updateLantern();
}); });
m_plugin.saveRegions(); 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); RegionPostBuilder builder = new RegionPostBuilder(destination.get(), m_plugin);
builder.updateLantern(); 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 { } else {
player.sendMessage("There is no region with that name. This is a bug."); 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.addItemFlags(ItemFlag.HIDE_ENCHANTS);
meta.addEnchant(Enchantment.SOUL_SPEED, 1, true); 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 + "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 + "Population: " + ChatColor.YELLOW + m_plugin.playerWatcher().playersInRegion(region).size());
lore.add(ChatColor.WHITE + "Altitude: " + ChatColor.YELLOW + altitude); lore.add(ChatColor.WHITE + "Altitude: " + ChatColor.YELLOW + altitude);
@ -180,6 +197,9 @@ public class PlayerInventoryTeleporter implements Listener {
} }
} }
lore.add("Nearby connections: " + String.join(", ", neighborNames)); 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 { } else {
lore.add("" + ChatColor.BOLD + ChatColor.GOLD + "You haven't discovered this location yet!"); 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()))); lore.add(ChatColor.WHITE + "Distance: " + ChatColor.YELLOW + ChatColor.MAGIC + Math.round(region.location().distance(event.region.location())));

View File

@ -6,8 +6,12 @@ import org.bukkit.scheduler.BukkitTask;
import org.bukkit.Particle; import org.bukkit.Particle;
import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause; import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
import org.bukkit.scheduler.BukkitScheduler; import org.bukkit.scheduler.BukkitScheduler;
import org.bukkit.ChatColor;
import org.bukkit.World; import org.bukkit.World;
import org.bukkit.Sound; import org.bukkit.Sound;
import org.bukkit.block.BlockFace;
import org.bukkit.block.Block;
import java.util.Random;
import io.papermc.lib.PaperLib; import io.papermc.lib.PaperLib;
import us.camin.regions.Plugin; import us.camin.regions.Plugin;
@ -15,6 +19,7 @@ import java.util.logging.Logger;
import org.bukkit.potion.PotionEffectType; import org.bukkit.potion.PotionEffectType;
import org.bukkit.potion.PotionEffect; import org.bukkit.potion.PotionEffect;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import org.bukkit.util.Vector;
public class PlayerTeleporter { public class PlayerTeleporter {
Logger log = Logger.getLogger("Regions.PlayerTeleporter"); Logger log = Logger.getLogger("Regions.PlayerTeleporter");
@ -23,12 +28,30 @@ public class PlayerTeleporter {
private Location m_src; private Location m_src;
private Location m_dest; private Location m_dest;
private Plugin m_plugin; 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_player = p;
this.m_src = src; this.m_src = src;
this.m_dest = dest; this.m_dest = dest;
this.m_plugin = plugin; 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<Void> teleport() { public CompletableFuture<Void> teleport() {
@ -37,6 +60,22 @@ public class PlayerTeleporter {
BukkitTask hoverGenerator = scheduler.runTaskTimer(m_plugin, () -> applyHoverEffect(), 0, 10); BukkitTask hoverGenerator = scheduler.runTaskTimer(m_plugin, () -> applyHoverEffect(), 0, 10);
BukkitTask particleGenerator = scheduler.runTaskTimer(m_plugin, () -> spawnHoverParticles(), 0, 1); 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(); playTeleportSound();
m_plugin.getServer().getScheduler().runTaskLater(m_plugin, () -> { m_plugin.getServer().getScheduler().runTaskLater(m_plugin, () -> {
@ -46,11 +85,23 @@ public class PlayerTeleporter {
m_plugin.getServer().getScheduler().runTaskLater(m_plugin, () -> { m_plugin.getServer().getScheduler().runTaskLater(m_plugin, () -> {
spawnTeleportStartParticles(); spawnTeleportStartParticles();
PaperLib.teleportAsync(m_player, m_dest, TeleportCause.COMMAND).thenAccept(res -> { 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.BLINDNESS, 60, 1, false, false, false));
m_player.addPotionEffect(new PotionEffect(PotionEffectType.SLOW, 40, 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(); spawnEndParticles();
particleGenerator.cancel(); particleGenerator.cancel();
hoverGenerator.cancel(); hoverGenerator.cancel();
noiseGenerator.cancel();
ret.complete(null); ret.complete(null);
}); });
}, 20 * 6); }, 20 * 6);
@ -63,11 +114,22 @@ public class PlayerTeleporter {
} }
void spawnEndParticles() { 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.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.CLOUD, m_dest, 70, 1, 1, 1);
world.spawnParticle(Particle.SPELL_MOB, m_dest, 5, 2, 2, 2); world.spawnParticle(Particle.SPELL_MOB, m_dest, 5, 2, 2, 2);
world.spawnParticle(Particle.PORTAL, m_player.getLocation(), 70, 1, 1, 1); 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() { 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_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_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); 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);
}
} }
} }