diff --git a/src/main/java/moe/oko/opennaw/OpenNAW.java b/src/main/java/moe/oko/opennaw/OpenNAW.java index bc977e5..35f9b53 100644 --- a/src/main/java/moe/oko/opennaw/OpenNAW.java +++ b/src/main/java/moe/oko/opennaw/OpenNAW.java @@ -2,13 +2,11 @@ package moe.oko.opennaw; import moe.oko.opennaw.command.CityCommand; import moe.oko.opennaw.command.NationCommand; +import moe.oko.opennaw.listener.ActionListener; import moe.oko.opennaw.util.*; import net.luckperms.api.LuckPerms; import org.bukkit.Bukkit; import org.bukkit.plugin.java.JavaPlugin; -import org.dynmap.DynmapCommonAPI; -import org.dynmap.DynmapCommonAPIListener; -import org.dynmap.bukkit.DynmapPlugin; import static moe.oko.opennaw.util.CommandHelper.info; @@ -16,7 +14,13 @@ public final class OpenNAW extends JavaPlugin { public static OpenNAW instance; public NationHandler nationHandler; + + public ActionLogger actionLogger; + public CityHandler cityHandler; + + public ConfigHelper configHelper; + public GroupHandler groupHandler; private LuckPerms luckPerms; @@ -38,7 +42,9 @@ public final class OpenNAW extends JavaPlugin { public void onEnable() { // Initialize internals instance = this; + configHelper = new ConfigHelper(this.getConfig()); this.luckPerms = getServer().getServicesManager().load(LuckPerms.class); + actionLogger = new ActionLogger(); nationHandler = new NationHandler(); cityHandler = new CityHandler(); groupHandler = new GroupHandler(this.luckPerms); @@ -49,6 +55,7 @@ public final class OpenNAW extends JavaPlugin { this.getCommand("nation").setExecutor(new NationCommand()); this.getCommand("city").setExecutor(new CityCommand()); getServer().getPluginManager().registerEvents(new ChatHandler(), this); + getServer().getPluginManager().registerEvents(new ActionListener(), this); if(Bukkit.getPluginManager().isPluginEnabled("dynmap")) { this.dynmapEnabled = true; @@ -69,4 +76,12 @@ public final class OpenNAW extends JavaPlugin { public DynmapHandler getDynmapHandler() { return dynmapHandler; } + + public ActionLogger getActionLogger() { + return actionLogger; + } + + public ConfigHelper getConfigHelper() { + return configHelper; + } } diff --git a/src/main/java/moe/oko/opennaw/listener/ActionListener.java b/src/main/java/moe/oko/opennaw/listener/ActionListener.java new file mode 100644 index 0000000..6930c40 --- /dev/null +++ b/src/main/java/moe/oko/opennaw/listener/ActionListener.java @@ -0,0 +1,31 @@ +package moe.oko.opennaw.listener; + +import moe.oko.opennaw.OpenNAW; +import moe.oko.opennaw.model.action.CityAttackAction; +import moe.oko.opennaw.model.action.CityDefenseAction; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.block.Action; +import org.bukkit.event.player.PlayerInteractEvent; + +public class ActionListener implements Listener { + + @EventHandler + public void onBlockInteract(PlayerInteractEvent event) { + if(event.getAction().equals(Action.RIGHT_CLICK_BLOCK)) { + //Right Click Logic + if(OpenNAW.getInstance().getCityHandler().isLocationAPoint(event.getClickedBlock().getLocation())) { + var city = OpenNAW.getInstance().getCityHandler().fetchCityViaPoint(event.getClickedBlock().getLocation()); + if(!OpenNAW.getInstance().getNationHandler().isPlayerInNation(event.getPlayer(), city.getOwner())) { + //Player is not in nation and just clicked point, attempt our interaction. + OpenNAW.getInstance().getActionLogger().tryAction(new CityAttackAction(event.getPlayer(), city)); + } else { + if(city.underSiege()) { + //Under siege, try to defend. + OpenNAW.getInstance().getActionLogger().tryAction(new CityDefenseAction(event.getPlayer(), city)); + } + } + } + } + } +} diff --git a/src/main/java/moe/oko/opennaw/model/City.java b/src/main/java/moe/oko/opennaw/model/City.java index 92b95f1..c17f99e 100644 --- a/src/main/java/moe/oko/opennaw/model/City.java +++ b/src/main/java/moe/oko/opennaw/model/City.java @@ -2,17 +2,18 @@ package moe.oko.opennaw.model; import moe.oko.opennaw.OpenNAW; import net.kyori.adventure.text.Component; -import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; -import net.md_5.bungee.api.chat.TextComponent; -import org.bukkit.Bukkit; -import org.bukkit.ChatColor; -import org.bukkit.Location; + +import org.bukkit.*; public class City { private String name; private String resource; private CityState state; private Nation owner; + + //Null until its needed. + private Nation attacker; + private Location point; private short health; @@ -40,7 +41,6 @@ public class City { public void setOwner(Nation nation) { this.owner = nation; - capture(); } public Location getPoint() { @@ -55,7 +55,62 @@ public class City { this.health -= damage; } + public boolean underSiege() { + return state.equals(CityState.SIEGE); + } + + public void startSiege(Nation nation) { + state = CityState.SIEGE; + Bukkit.broadcast(Component.text(ChatColor.RED + nation.getName() + ChatColor.GOLD + " has begun a siege against the city of " + ChatColor.AQUA + getName())); + for(var player : Bukkit.getOnlinePlayers()) { + player.playSound(player.getLocation(), Sound.ITEM_TRIDENT_THUNDER, 1F, 1F); + } + attacker = nation; + } + + public void damage() { + //Ran each time a city is damaged by a capture event + //Makes an explosion of ash around a block + point.getWorld().spawnParticle(Particle.ASH, point, 4000, .5, .5, .5); + point.getWorld().playSound(point, Sound.ENTITY_GENERIC_EXPLODE, 1F, 1F); + health = (short) (health - OpenNAW.getInstance().getConfigHelper().cityDamageOnStrike()); + switch (health) { + case 250: + case 200: + case 150: + case 100: + case 50: + for(var player : Bukkit.getOnlinePlayers()) { + if(player.getLocation().distance(point) < 100) { + player.sendMessage(ChatColor.BOLD + "" + ChatColor.RED + "THE CITY HAS FALLEN TO " + health + " HEALTH..."); + } + } + case 10: + for(var player : Bukkit.getOnlinePlayers()) { + if(player.getLocation().distance(point) < 100) { + player.sendMessage(ChatColor.BOLD + "" + ChatColor.RED + "THE CITY IS ABOUT TO BE CAPTURED!"); + } + } + } + if(health == 0 || health < 0) { + capture(); + } + } + + public void defend() { + //successful defense logic. + Bukkit.broadcast(Component.text(ChatColor.RED + attacker.getName() + ChatColor.GOLD + "'s siege against the city of " + + ChatColor.AQUA + getName() + ChatColor.GOLD + " has " + ChatColor.RED + "failed")); + if(health < 250) { + health = (short) (health + 50); + } + OpenNAW.getInstance().getActionLogger().cancelDefenseActions(this); + attacker = null; + } + public void capture() { + setOwner(attacker); + attacker = null; //reset to null so there isn't any bugs //This is our "capture" logic. So now we do shenanigans. if(OpenNAW.getInstance().isDynmapEnabled()) { //Dyn is enabled, we need to do setters. diff --git a/src/main/java/moe/oko/opennaw/model/Nation.java b/src/main/java/moe/oko/opennaw/model/Nation.java index 8cbbdd3..b9365ed 100644 --- a/src/main/java/moe/oko/opennaw/model/Nation.java +++ b/src/main/java/moe/oko/opennaw/model/Nation.java @@ -2,6 +2,10 @@ package moe.oko.opennaw.model; import net.luckperms.api.model.group.Group; import org.bukkit.Location; +import org.bukkit.OfflinePlayer; + +import java.util.HashMap; +import java.util.UUID; public class Nation { public static final Nation UNCLAIMED = new Nation("UNCLAIMED", null); @@ -10,16 +14,28 @@ public class Nation { private Group group; private Location spawn; + private HashMap players; + //The icon used for cities owned by this nation (default is a tower) private String dynmapIcon; public Nation(String name, Group group) { this.name = name; this.group = group; + this.players = new HashMap<>(); this.dynmapIcon = "tower"; this.spawn = null; } + //Db Constructor + public Nation(String name, Group group, HashMap players, String dynmapIcon, Location spawn) { + this.name = name; + this.group = group; + this.players = players; + this.dynmapIcon = dynmapIcon; + this.spawn = spawn; + } + public String getName() { return name; } public Group getGroup() { return group; } public Location getSpawn() { return spawn; } @@ -31,6 +47,10 @@ public class Nation { return dynmapIcon; } + public HashMap getPlayerMap() { + return players; + } + public void setDynmapIcon(String dynmapIcon) { this.dynmapIcon = dynmapIcon; } diff --git a/src/main/java/moe/oko/opennaw/model/action/CityAttackAction.java b/src/main/java/moe/oko/opennaw/model/action/CityAttackAction.java index 170fd1d..f6ba340 100644 --- a/src/main/java/moe/oko/opennaw/model/action/CityAttackAction.java +++ b/src/main/java/moe/oko/opennaw/model/action/CityAttackAction.java @@ -1,12 +1,19 @@ package moe.oko.opennaw.model.action; +import moe.oko.opennaw.OpenNAW; import moe.oko.opennaw.model.City; +import moe.oko.opennaw.model.Nation; +import org.bukkit.ChatColor; import org.bukkit.OfflinePlayer; +import org.bukkit.Sound; public class CityAttackAction extends Action{ public static final long DELAY = 10000L; + public OfflinePlayer player; + public City city; + public OfflinePlayer getPlayer() { return player; } @@ -14,9 +21,23 @@ public class CityAttackAction extends Action{ public CityAttackAction(OfflinePlayer player, City city) { this.timeOfAction = System.currentTimeMillis(); this.player = player; + this.city = city; + } + + public void initiation() { + if(!city.underSiege()) { + var nation = OpenNAW.getInstance().getNationHandler().getNationByPlayer(player.getUniqueId()); + //Initiate siege. + city.startSiege(nation); + } + city.getPoint().getWorld().playSound(city.getPoint(), Sound.ENTITY_FIREWORK_ROCKET_BLAST, 1, 1); } public void completion() { - + //Completion logic... + if(!player.isOnline()) { return; } + var online = player.getPlayer(); + online.sendMessage(ChatColor.GREEN + "Action Completed"); + city.damage(); } } diff --git a/src/main/java/moe/oko/opennaw/model/action/CityDefenseAction.java b/src/main/java/moe/oko/opennaw/model/action/CityDefenseAction.java new file mode 100644 index 0000000..2163d09 --- /dev/null +++ b/src/main/java/moe/oko/opennaw/model/action/CityDefenseAction.java @@ -0,0 +1,40 @@ +package moe.oko.opennaw.model.action; + +import moe.oko.opennaw.OpenNAW; +import moe.oko.opennaw.model.City; +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.OfflinePlayer; +import org.bukkit.entity.Player; + +public class CityDefenseAction extends Action { + + //60 seconds for defense action + public static final long DELAY = 60000L; + + public OfflinePlayer player; + + public City city; + + public CityDefenseAction(OfflinePlayer player, City city) { + this.timeOfAction = System.currentTimeMillis(); + this.player = player; + this.city = city; + } + + public void initiation() { + for(var player : Bukkit.getOnlinePlayers()) { + if(player.getLocation().distance(city.getPoint()) < 100) { + player.sendMessage(ChatColor.RED + "" + ChatColor.BOLD + player.getName() + " HAS STARTED DEFENDING THE POINT."); + } + } + } + + public void completion() { + city.defend(); + } + + public OfflinePlayer getPlayer() { + return player; + } +} diff --git a/src/main/java/moe/oko/opennaw/util/ActionLogger.java b/src/main/java/moe/oko/opennaw/util/ActionLogger.java index ffdef2e..3f67aac 100644 --- a/src/main/java/moe/oko/opennaw/util/ActionLogger.java +++ b/src/main/java/moe/oko/opennaw/util/ActionLogger.java @@ -1,9 +1,12 @@ package moe.oko.opennaw.util; import moe.oko.opennaw.OpenNAW; +import moe.oko.opennaw.model.City; import moe.oko.opennaw.model.action.Action; import moe.oko.opennaw.model.action.CityAttackAction; +import moe.oko.opennaw.model.action.CityDefenseAction; import org.bukkit.Bukkit; +import org.bukkit.ChatColor; import java.util.HashMap; import java.util.UUID; @@ -21,8 +24,10 @@ public class ActionLogger { CityAttackAction CAA = (CityAttackAction) action; if (actionByUuid.containsKey(CAA.getPlayer().getUniqueId())) { actionByUuid.remove(CAA.getPlayer().getUniqueId()); + CAA.getPlayer().getPlayer().sendMessage(ChatColor.YELLOW + "Action switched."); } actionByUuid.put(CAA.getPlayer().getUniqueId(), action); + CAA.initiation(); //Code to run when action started. Bukkit.getScheduler().scheduleSyncDelayedTask(OpenNAW.getInstance(), () -> { var actionCallback = actionByUuid.get(CAA.getPlayer().getUniqueId()); if (!actionCallback.isCancelled()) { @@ -33,10 +38,42 @@ public class ActionLogger { return true; } return false; + } else if(action instanceof CityDefenseAction) { + if(enoughTimeElapsed(action.timeOfAction, CityDefenseAction.DELAY)) { + CityDefenseAction CDA = (CityDefenseAction) action; + if (actionByUuid.containsKey(CDA.getPlayer().getUniqueId())) { + actionByUuid.remove(CDA.getPlayer().getUniqueId()); + CDA.getPlayer().getPlayer().sendMessage(ChatColor.YELLOW + "Action switched."); + } + actionByUuid.put(CDA.getPlayer().getUniqueId(), action); + CDA.initiation(); //Code to run when action started. + Bukkit.getScheduler().scheduleSyncDelayedTask(OpenNAW.getInstance(), () -> { + var actionCallback = actionByUuid.get(CDA.getPlayer().getUniqueId()); + if (!actionCallback.isCancelled()) { + CDA.completion(); + } + actionByUuid.remove(CDA.getPlayer().getUniqueId()); + }, CityDefenseAction.DELAY); + return true; + } } return false; } + public void cancelDefenseActions(City city) { + for(var action : actionByUuid.values()) { + if(action instanceof CityDefenseAction) { + var cda = (CityDefenseAction) action; + if(cda.city == city) { + if(cda.getPlayer().isOnline()) { + cda.getPlayer().getPlayer().sendMessage(ChatColor.RED + "Action failed."); + } + cda.setCancelled(true); + } + } + } + } + private boolean enoughTimeElapsed(long timestamp, long delay) { return (System.currentTimeMillis() - timestamp) > delay; } diff --git a/src/main/java/moe/oko/opennaw/util/CityHandler.java b/src/main/java/moe/oko/opennaw/util/CityHandler.java index 2fa1872..1807455 100644 --- a/src/main/java/moe/oko/opennaw/util/CityHandler.java +++ b/src/main/java/moe/oko/opennaw/util/CityHandler.java @@ -21,6 +21,24 @@ public class CityHandler { public void setCityOwner(City city, Nation nation) { cities.get(city.getName()).setOwner(nation); } + public boolean isLocationAPoint(Location loc) { + for(City cty : cities.values()) { + if(cty.getPoint().equals(loc)) { + return true; + } + } + return false; + } + + public City fetchCityViaPoint(Location location) { + for(City cty : cities.values()) { + if(cty.getPoint().equals(location)) { + return cty; + } + } + return null; + } + public List getCityList() { List cityList = new ArrayList(); for (City city : cities.values()) { diff --git a/src/main/java/moe/oko/opennaw/util/ConfigHelper.java b/src/main/java/moe/oko/opennaw/util/ConfigHelper.java new file mode 100644 index 0000000..1977eb0 --- /dev/null +++ b/src/main/java/moe/oko/opennaw/util/ConfigHelper.java @@ -0,0 +1,16 @@ +package moe.oko.opennaw.util; + +import org.bukkit.configuration.Configuration; + +public class ConfigHelper { + private Configuration config; + + public ConfigHelper(Configuration config) { + this.config = config; + } + + //Damage a city takes when a point is striked + public int cityDamageOnStrike() { + return config.getConfigurationSection("city").getInt("damageOnStrike"); + } +} diff --git a/src/main/java/moe/oko/opennaw/util/NationHandler.java b/src/main/java/moe/oko/opennaw/util/NationHandler.java index eb422b4..08543a5 100644 --- a/src/main/java/moe/oko/opennaw/util/NationHandler.java +++ b/src/main/java/moe/oko/opennaw/util/NationHandler.java @@ -2,10 +2,12 @@ package moe.oko.opennaw.util; import moe.oko.opennaw.model.Nation; import net.luckperms.api.model.group.Group; +import org.bukkit.entity.Player; import java.util.ArrayList; import java.util.HashMap; import java.util.List; +import java.util.UUID; public class NationHandler { @@ -23,6 +25,19 @@ public class NationHandler { return nations.get(name).getGroup(); } + public boolean isPlayerInNation(Player player, Nation nation) { + return nation.getPlayerMap().containsKey(player.getUniqueId()); + } + + public Nation getNationByPlayer(UUID uuid) { + for(var nation : nations.values()) { + if(nation.getPlayerMap().containsKey(uuid)) { + return nation; + } + } + return null; + } + public List getNationList() { List nationList = new ArrayList(); for (Nation nation : nations.values()) { diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 7ee6f17..5d53a1f 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -1,2 +1,4 @@ # OpenNAW Configuration - +city: + #The amount of damage a city takes on the point being striked + damageOnStrike: 5 \ No newline at end of file