From f046154b00fa0c2fdeb0d1942f6d60d9416bd232 Mon Sep 17 00:00:00 2001 From: LlmDl Date: Thu, 21 Dec 2023 17:35:52 -0600 Subject: [PATCH] Add the ability for nations to sanction towns, preventing them from joining the nation via invite or join. (#7129) * Add the ability for nations to sanction towns, preventing them from joining the nation via invite or join. Closes #6544. * Forgot a lang string. * Add admin command * Can't forget about the name blacklist! * Fix lang strings, add ability to /n sanctiontown list [nation], add events. --- .../bukkit/towny/command/HelpMenu.java | 11 +++ .../bukkit/towny/command/NationCommand.java | 98 ++++++++++++++++++- .../towny/command/TownyAdminCommand.java | 28 ++++-- .../bukkit/towny/db/SQLSchema.java | 1 + .../bukkit/towny/db/TownyFlatFileSource.java | 8 ++ .../bukkit/towny/db/TownySQLSource.java | 7 +- .../nation/NationSanctionTownAddEvent.java | 38 +++++++ .../nation/NationSanctionTownRemoveEvent.java | 38 +++++++ .../bukkit/towny/object/Nation.java | 32 ++++++ .../towny/permissions/PermissionNodes.java | 2 + .../bukkit/util/NameValidation.java | 2 +- Towny/src/main/resources/lang/en-US.yml | 27 ++++- Towny/src/main/resources/plugin.yml | 2 + 13 files changed, 282 insertions(+), 12 deletions(-) create mode 100644 Towny/src/main/java/com/palmergames/bukkit/towny/event/nation/NationSanctionTownAddEvent.java create mode 100644 Towny/src/main/java/com/palmergames/bukkit/towny/event/nation/NationSanctionTownRemoveEvent.java diff --git a/Towny/src/main/java/com/palmergames/bukkit/towny/command/HelpMenu.java b/Towny/src/main/java/com/palmergames/bukkit/towny/command/HelpMenu.java index 128c0c6ddd..34f710ef39 100644 --- a/Towny/src/main/java/com/palmergames/bukkit/towny/command/HelpMenu.java +++ b/Towny/src/main/java/com/palmergames/bukkit/towny/command/HelpMenu.java @@ -937,6 +937,17 @@ protected MenuBuilder load() { } }, + NATION_SANCTIONTOWN { + @Override + protected MenuBuilder load() { + return new MenuBuilder("nation sanctiontown") + .add("add [town]", Translatable.of("nation_sanction_help_1")) + .add("remove [town]", Translatable.of("nation_sanction_help_2")) + .add("list", Translatable.of("nation_sanction_help_3")) + .add("list [nation]", Translatable.of("nation_sanction_help_4")); + } + }, + ALLIES_STRING { @Override protected MenuBuilder load() { diff --git a/Towny/src/main/java/com/palmergames/bukkit/towny/command/NationCommand.java b/Towny/src/main/java/com/palmergames/bukkit/towny/command/NationCommand.java index 59d61a0f62..aee7927a0f 100644 --- a/Towny/src/main/java/com/palmergames/bukkit/towny/command/NationCommand.java +++ b/Towny/src/main/java/com/palmergames/bukkit/towny/command/NationCommand.java @@ -17,6 +17,8 @@ import com.palmergames.bukkit.towny.event.NationPreRemoveEnemyEvent; import com.palmergames.bukkit.towny.event.nation.NationRankAddEvent; import com.palmergames.bukkit.towny.event.nation.NationRankRemoveEvent; +import com.palmergames.bukkit.towny.event.nation.NationSanctionTownAddEvent; +import com.palmergames.bukkit.towny.event.nation.NationSanctionTownRemoveEvent; import com.palmergames.bukkit.towny.event.nation.NationSetSpawnEvent; import com.palmergames.bukkit.towny.event.nation.NationTownLeaveEvent; import com.palmergames.bukkit.towny.event.NationRemoveEnemyEvent; @@ -125,6 +127,7 @@ public class NationCommand extends BaseCommand implements CommandExecutor { "enemylist", "ally", "spawn", + "sanctiontown", "king", "leader", "bankhistory", @@ -235,6 +238,18 @@ else if (args.length == 3) if (args.length == 3) { return Collections.singletonList("-ignore"); } + case "sanctiontown": + if (args.length == 2) + return NameUtil.filterByStart(Arrays.asList("add", "remove", "list"), args[1]); + if (args.length == 3 && args[1].equalsIgnoreCase("add") || args[1].equalsIgnoreCase("remove")) + return NameUtil.filterByStart(TownyUniverse.getInstance().getTowns() + .stream() + .filter(t -> !nation.hasTown(t)) + .map(Town::getName) + .collect(Collectors.toList()), args[2]); + if (args.length == 3 && args[1].equalsIgnoreCase("list")) + return getTownyStartingWith(args[2], "n"); + break; case "add": return getTownyStartingWith(args[args.length - 1], "t"); case "kick": @@ -528,6 +543,9 @@ public void parseNationCommand(final Player player, String[] split) throws Towny checkPermOrThrow(player, PermissionNodes.TOWNY_COMMAND_NATION_KICK.getNode()); nationKick(player, StringMgmt.remFirstArg(split)); break; + case "sanctiontown": + nationSanctionTown(player, null, StringMgmt.remFirstArg(split)); + break; case "set": /* Permission test is internal*/ nationSet(player, StringMgmt.remFirstArg(split), false, null); @@ -666,7 +684,11 @@ private void parseNationJoin(Player player, String[] args) { // Check if town is town is free to join. if (!nation.isOpen()) throw new TownyException(Translatable.of("msg_err_nation_not_open", nation.getFormattedName())); - + + // Check if the town is sanctioned and not allowed to join. + if (nation.hasSanctionedTown(town)) + throw new TownyException(Translatable.of("msg_err_cannot_join_nation_sanctioned_town", nation.getName())); + if (!testTownHasEnoughResidents(town)) throw new TownyException(Translatable.of("msg_err_not_enough_residents_join_nation", town.getName())); @@ -1180,6 +1202,13 @@ public void nationAdd(Player player, String[] names) throws TownyException { continue; } + if (nation.hasSanctionedTown(town)) { + // Town is sanctioned and cannot join. + removeinvites.add(townname); + TownyMessaging.sendErrorMsg(player, Translatable.of("msg_err_cannot_add_sanctioned_town", townname)); + continue; + } + if (!testNationMaxResidents(nation, town)) { // Town has too many residents to join the nation removeinvites.add(townname); @@ -1398,6 +1427,73 @@ public static void nationKick(CommandSender sender, Nation nation, List ki TownyMessaging.sendErrorMsg(sender, Translatable.of("msg_invalid_name")); } + public static void nationSanctionTown(CommandSender sender, Nation nation, String[] args) throws TownyException { + if (args.length == 0 || args[0].equals("?")) { + HelpMenu.NATION_SANCTIONTOWN.send(sender); + return; + } + + if (nation == null && sender instanceof Player player) + nation = getNationFromPlayerOrThrow(player); + + if (nation == null) + throw new TownyException(Translatable.of("msg_err_no_nation_cannot_do")); + + if (args[0].toLowerCase(Locale.ROOT).equals("list")) { + if (args.length == 2) + nation = getNationOrThrow(args[1]); + nationSanctionTownList(sender, nation); + return; + } + + if (args.length != 2) { + HelpMenu.NATION_SANCTIONTOWN.send(sender); + return; + } + checkPermOrThrow(sender, PermissionNodes.TOWNY_COMMAND_NATION_SANCTIONTOWN.getNode()); + Town town = getTownOrThrow(args[1]); + switch(args[0].toLowerCase(Locale.ROOT)) { + case "add" -> nationSanctionTownAdd(sender, nation, town); + case "remove" -> nationSactionTownRemove(sender, nation, town); + default -> HelpMenu.NATION_SANCTIONTOWN.send(sender); + } + } + + private static void nationSanctionTownList(CommandSender sender, Nation nation) { + if (nation.getSanctionedTowns().isEmpty()) { + TownyMessaging.sendMsg(sender, Translatable.of("msg_err_nation_has_no_sanctioned_towns")); + return; + } + Translator translator = Translator.locale(sender); + TownyMessaging.sendMessage(sender, ChatTools.formatTitle(nation.getName() + " " + translator.of("title_nation_sanctioned_towns"))); + TownyMessaging.sendMessage(sender, TownyFormatter.getFormattedTownyObjects(translator.of("title_nation_sanctioned_towns"), new ArrayList<>(nation.getSanctionedTowns()))); + } + + private static void nationSanctionTownAdd(CommandSender sender, Nation nation, Town town) throws TownyException { + if (nation.hasTown(town)) + throw new TownyException(Translatable.of("msg_err_nation_cannot_sanction_own_town")); + + if (nation.hasSanctionedTown(town)) + throw new TownyException(Translatable.of("msg_err_nation_town_already_sanctioned")); + + BukkitTools.ifCancelledThenThrow(new NationSanctionTownAddEvent(nation, town)); + + nation.addSanctionedTown(town); + nation.save(); + TownyMessaging.sendMsg(sender, Translatable.of("msg_err_nation_town_sanctioned", town.getName())); + } + + private static void nationSactionTownRemove(CommandSender sender, Nation nation, Town town) throws TownyException { + if (!nation.hasSanctionedTown(town)) + throw new TownyException(Translatable.of("msg_err_nation_town_isnt_sanctioned")); + + BukkitTools.ifCancelledThenThrow(new NationSanctionTownRemoveEvent(nation, town)); + + nation.removeSanctionedTown(town); + nation.save(); + TownyMessaging.sendMsg(sender, Translatable.of("msg_err_nation_town_unsanctioned", town.getName())); + } + private void nationAlly(Player player, String[] split) throws TownyException { if (split.length == 0) { HelpMenu.ALLIES_STRING.send(player); diff --git a/Towny/src/main/java/com/palmergames/bukkit/towny/command/TownyAdminCommand.java b/Towny/src/main/java/com/palmergames/bukkit/towny/command/TownyAdminCommand.java index 5172e148ff..f2614b2077 100644 --- a/Towny/src/main/java/com/palmergames/bukkit/towny/command/TownyAdminCommand.java +++ b/Towny/src/main/java/com/palmergames/bukkit/towny/command/TownyAdminCommand.java @@ -172,6 +172,7 @@ public class TownyAdminCommand extends BaseCommand implements CommandExecutor { "rename", "delete", "toggle", + "sanctiontown", "set", "meta", "deposit", @@ -508,6 +509,9 @@ else if (args.length > 3 && TownyCommandAddonAPI.hasCommand(CommandType.TOWNYADM if (args.length == 2) { return filterByStartOrGetTownyStartingWith(Collections.singletonList("new"), args[1], "+n"); } else if (args.length > 2 && !args[1].equalsIgnoreCase("new")) { + Nation nation = TownyUniverse.getInstance().getNation(args[1]); + if (nation == null) + return Collections.emptyList(); switch (args[2].toLowerCase(Locale.ROOT)) { case "add": if (args.length == 4) @@ -518,14 +522,8 @@ else if (args.length > 3 && TownyCommandAddonAPI.hasCommand(CommandType.TOWNYADM else if (args.length == 5) return NameUtil.filterByStart(BaseCommand.setOnOffCompletes, args[4]); case "set": { - Nation nation = TownyUniverse.getInstance().getNation(args[1]); - if (nation != null) { - if (args.length == 4) { - return NameUtil.filterByStart(adminNationSetTabCompletes, args[3]); - } - } - else { - return Collections.emptyList(); + if (args.length == 4) { + return NameUtil.filterByStart(adminNationSetTabCompletes, args[3]); } } case "meta": @@ -546,6 +544,16 @@ else if (args.length == 5) return getTownyStartingWith(args[4], "r"); else if (args.length == 6) return NameUtil.filterByStart(TownyPerms.getNationRanks(), args[5]); + case "sanctiontown": + if (args.length == 4) + return NameUtil.filterByStart(Arrays.asList("add","remove","list"), args[3]); + if (args.length == 5 && args[3].equalsIgnoreCase("add") || args[4].equalsIgnoreCase("remove")) + return NameUtil.filterByStart(TownyUniverse.getInstance().getTowns() + .stream() + .filter(t -> !nation.hasTown(t)) + .map(Town::getName) + .collect(Collectors.toList()), args[4]); + break; case "enemy": case "ally": if (args.length == 4) @@ -1633,6 +1641,10 @@ public void parseAdminNationCommand(CommandSender sender, String[] split) throws checkPermOrThrow(sender, PermissionNodes.TOWNY_COMMAND_TOWNYADMIN_NATION_KICK.getNode()); NationCommand.nationKick(sender, nation, TownyAPI.getInstance().getTowns(StringMgmt.remArgs(split, 2))); break; + case "sanctiontown": + checkPermOrThrow(sender, PermissionNodes.TOWNY_COMMAND_TOWNYADMIN_NATION_SANCTIONTOWN.getNode()); + NationCommand.nationSanctionTown(sender, nation, StringMgmt.remArgs(split, 2)); + break; case "delete": checkPermOrThrow(sender, PermissionNodes.TOWNY_COMMAND_TOWNYADMIN_NATION_DELETE.getNode()); Confirmation.runOnAccept(() -> { diff --git a/Towny/src/main/java/com/palmergames/bukkit/towny/db/SQLSchema.java b/Towny/src/main/java/com/palmergames/bukkit/towny/db/SQLSchema.java index db381c9024..7f59bfadd2 100644 --- a/Towny/src/main/java/com/palmergames/bukkit/towny/db/SQLSchema.java +++ b/Towny/src/main/java/com/palmergames/bukkit/towny/db/SQLSchema.java @@ -269,6 +269,7 @@ private static List getNationColumns(){ columns.add("`isOpen` bool NOT NULL DEFAULT '1'"); columns.add("`metadata` text DEFAULT NULL"); columns.add("`conqueredTax` float NOT NULL"); + columns.add("`sanctionedTowns` mediumtext DEFAULT NULL"); return columns; } diff --git a/Towny/src/main/java/com/palmergames/bukkit/towny/db/TownyFlatFileSource.java b/Towny/src/main/java/com/palmergames/bukkit/towny/db/TownyFlatFileSource.java index 7c95e759c7..db38f3f0a5 100644 --- a/Towny/src/main/java/com/palmergames/bukkit/towny/db/TownyFlatFileSource.java +++ b/Towny/src/main/java/com/palmergames/bukkit/towny/db/TownyFlatFileSource.java @@ -1218,6 +1218,11 @@ public boolean loadNation(Nation nation) { if (line != null && !line.isEmpty()) nation.setConqueredTax(Double.parseDouble(line)); + line = keys.get("sanctionedTowns"); + if (line != null) { + nation.loadSanctionedTowns(line.split("#")); + } + } catch (Exception e) { plugin.getLogger().log(Level.WARNING, Translation.of("flatfile_err_reading_nation_file_at_line", nation.getName(), line, nation.getName()), e); return false; @@ -2136,6 +2141,9 @@ public boolean saveNation(Nation nation) { list.add("metadata=" + serializeMetadata(nation)); list.add("conqueredTax=" + nation.getConqueredTax()); + + // SanctionedTowns + list.add("sanctionedTowns=" + StringMgmt.join(nation.getSanctionedTownsForSaving(), "#")); /* * Make sure we only save in async */ diff --git a/Towny/src/main/java/com/palmergames/bukkit/towny/db/TownySQLSource.java b/Towny/src/main/java/com/palmergames/bukkit/towny/db/TownySQLSource.java index 5c54d58866..9c3e0cd008 100644 --- a/Towny/src/main/java/com/palmergames/bukkit/towny/db/TownySQLSource.java +++ b/Towny/src/main/java/com/palmergames/bukkit/towny/db/TownySQLSource.java @@ -1387,6 +1387,11 @@ private boolean loadNation(ResultSet rs) { } catch (SQLException ignored) { } + line = rs.getString("sanctionedTowns"); + if (line != null) { + nation.loadSanctionedTowns(line.split("#")); + } + return true; } catch (SQLException e) { TownyMessaging.sendErrorMsg("SQL: Load Nation " + name + " SQL Error - " + e.getMessage()); @@ -2349,7 +2354,7 @@ public synchronized boolean saveNation(Nation nation) { nat_hm.put("metadata", ""); nat_hm.put("conqueredTax", nation.getConqueredTax()); - + nat_hm.put("sanctionedTowns", StringMgmt.join(nation.getSanctionedTownsForSaving(), "#")); updateDB("NATIONS", nat_hm, Collections.singletonList("name")); } catch (Exception e) { diff --git a/Towny/src/main/java/com/palmergames/bukkit/towny/event/nation/NationSanctionTownAddEvent.java b/Towny/src/main/java/com/palmergames/bukkit/towny/event/nation/NationSanctionTownAddEvent.java new file mode 100644 index 0000000000..34f31113b0 --- /dev/null +++ b/Towny/src/main/java/com/palmergames/bukkit/towny/event/nation/NationSanctionTownAddEvent.java @@ -0,0 +1,38 @@ +package com.palmergames.bukkit.towny.event.nation; + +import com.palmergames.bukkit.towny.event.CancellableTownyEvent; +import com.palmergames.bukkit.towny.object.Nation; +import com.palmergames.bukkit.towny.object.Town; + +import org.bukkit.event.HandlerList; +import org.jetbrains.annotations.NotNull; + +public class NationSanctionTownAddEvent extends CancellableTownyEvent { + private static final HandlerList HANDLER_LIST = new HandlerList(); + + private final Nation nation; + private final Town town; + + public NationSanctionTownAddEvent(Nation nation, Town town) { + this.nation = nation; + this.town = town; + } + + public Nation getNation() { + return nation; + } + + public Town getTown() { + return town; + } + + public static HandlerList getHandlerList() { + return HANDLER_LIST; + } + + @NotNull + @Override + public HandlerList getHandlers() { + return HANDLER_LIST; + } +} diff --git a/Towny/src/main/java/com/palmergames/bukkit/towny/event/nation/NationSanctionTownRemoveEvent.java b/Towny/src/main/java/com/palmergames/bukkit/towny/event/nation/NationSanctionTownRemoveEvent.java new file mode 100644 index 0000000000..75517e988d --- /dev/null +++ b/Towny/src/main/java/com/palmergames/bukkit/towny/event/nation/NationSanctionTownRemoveEvent.java @@ -0,0 +1,38 @@ +package com.palmergames.bukkit.towny.event.nation; + +import com.palmergames.bukkit.towny.event.CancellableTownyEvent; +import com.palmergames.bukkit.towny.object.Nation; +import com.palmergames.bukkit.towny.object.Town; + +import org.bukkit.event.HandlerList; +import org.jetbrains.annotations.NotNull; + +public class NationSanctionTownRemoveEvent extends CancellableTownyEvent { + private static final HandlerList HANDLER_LIST = new HandlerList(); + + private final Nation nation; + private final Town town; + + public NationSanctionTownRemoveEvent(Nation nation, Town town) { + this.nation = nation; + this.town = town; + } + + public Nation getNation() { + return nation; + } + + public Town getTown() { + return town; + } + + public static HandlerList getHandlerList() { + return HANDLER_LIST; + } + + @NotNull + @Override + public HandlerList getHandlers() { + return HANDLER_LIST; + } +} diff --git a/Towny/src/main/java/com/palmergames/bukkit/towny/object/Nation.java b/Towny/src/main/java/com/palmergames/bukkit/towny/object/Nation.java index c57c5718e7..0f647454e2 100644 --- a/Towny/src/main/java/com/palmergames/bukkit/towny/object/Nation.java +++ b/Towny/src/main/java/com/palmergames/bukkit/towny/object/Nation.java @@ -34,6 +34,7 @@ import java.util.Collections; import java.util.List; import java.util.Objects; +import java.util.UUID; import java.util.stream.Collectors; public class Nation extends Government { @@ -41,6 +42,7 @@ public class Nation extends Government { private static final String ECONOMY_ACCOUNT_PREFIX = TownySettings.getNationAccountPrefix(); private final List towns = new ArrayList<>(); + private final List sanctionedTowns = new ArrayList<>(); private List allies = new ArrayList<>(); private List enemies = new ArrayList<>(); private Town capital; @@ -698,4 +700,34 @@ public int getLevel(int populationSize) { public void playerBroadCastMessageToNation(Player player, String message) { TownyMessaging.sendPrefixedNationMessage(this, Translatable.of("town_say_format", player.getName(), TownyComponents.stripClickTags(message))); } + + + public List getSanctionedTowns() { + return sanctionedTowns; + } + + public boolean hasSanctionedTown(Town town) { + return sanctionedTowns.contains(town); + } + + public void addSanctionedTown(Town town) { + if (!sanctionedTowns.contains(town)) + sanctionedTowns.add(town); + } + + public void removeSanctionedTown(Town town) { + sanctionedTowns.remove(town); + } + + public List getSanctionedTownsForSaving() { + return sanctionedTowns.stream().map(t -> t.getUUID().toString()).collect(Collectors.toList()); + } + + public void loadSanctionedTowns(String[] tokens) { + for (String stringUUID : tokens) { + UUID uuid = UUID.fromString(stringUUID); + if (uuid != null && TownyAPI.getInstance().getTown(uuid) != null) + sanctionedTowns.add(TownyAPI.getInstance().getTown(uuid)); + } + } } diff --git a/Towny/src/main/java/com/palmergames/bukkit/towny/permissions/PermissionNodes.java b/Towny/src/main/java/com/palmergames/bukkit/towny/permissions/PermissionNodes.java index f81f85110e..6c5a59dafe 100644 --- a/Towny/src/main/java/com/palmergames/bukkit/towny/permissions/PermissionNodes.java +++ b/Towny/src/main/java/com/palmergames/bukkit/towny/permissions/PermissionNodes.java @@ -90,6 +90,7 @@ public enum PermissionNodes { TOWNY_COMMAND_NATION_BANKHISTORY("towny.command.nation.bankhistory"), TOWNY_COMMAND_NATION_BALTOP("towny.command.nation.baltop"), TOWNY_COMMAND_NATION_KICK("towny.command.nation.kick"), + TOWNY_COMMAND_NATION_SANCTIONTOWN("towny.command.nation.sanctiontown"), /* * Town command permissions @@ -338,6 +339,7 @@ public enum PermissionNodes { TOWNY_COMMAND_TOWNYADMIN_NATION_RECHECK("towny.command.townyadmin.nation.recheck"), TOWNY_COMMAND_TOWNYADMIN_NATION_RENAME("towny.command.townyadmin.nation.rename"), TOWNY_COMMAND_TOWNYADMIN_NATION_MERGE("towny.command.townyadmin.nation.merge"), + TOWNY_COMMAND_TOWNYADMIN_NATION_SANCTIONTOWN("towny.command.townyadmin.nation.sanctiontown"), TOWNY_COMMAND_TOWNYADMIN_NATION_SET("towny.command.townyadmin.nation.set"), TOWNY_COMMAND_TOWNYADMIN_NATION_SETFOUNDINGDATE("towny.command.townyadmin.nation.set.foundingdate"), TOWNY_COMMAND_TOWNYADMIN_NATION_TOGGLE("towny.command.townyadmin.nation.toggle"), diff --git a/Towny/src/main/java/com/palmergames/bukkit/util/NameValidation.java b/Towny/src/main/java/com/palmergames/bukkit/util/NameValidation.java index 6bcc8d0395..8e90a68361 100644 --- a/Towny/src/main/java/com/palmergames/bukkit/util/NameValidation.java +++ b/Towny/src/main/java/com/palmergames/bukkit/util/NameValidation.java @@ -29,7 +29,7 @@ public class NameValidation { "outlawlist","deposit","outlaw","outpost","ranklist","rank","reclaim","reslist","say","set","toggle","join", "invite","buy","mayor","bankhistory","enemy","ally","townlist","allylist","enemylist","king","merge","jail", "plotgrouplist","trust","purge","leader","baltop","all","help", "spawn", "takeoverclaim", "ban", "unjail", - "trusttown","forsale","fs","notforsale","nfs","buytown")); + "trusttown","forsale","fs","notforsale","nfs","buytown","sanctiontown")); } /** diff --git a/Towny/src/main/resources/lang/en-US.yml b/Towny/src/main/resources/lang/en-US.yml index ebb3a4c368..c9b567b105 100644 --- a/Towny/src/main/resources/lang/en-US.yml +++ b/Towny/src/main/resources/lang/en-US.yml @@ -206,6 +206,11 @@ nation_toggle_help_1: "Toggles public status, allowing non-residents to use /n s nation_toggle_help_2: "Toggles open status, allowing towns to join without an invite." nation_toggle_help_3: "Toggles taxpercent, making towns pay a percentage instead of fixed rate." +nation_sanction_help_1: "Adds a town to the SanctionedTown list." +nation_sanction_help_2: "Removes a town from the SanctionedTown list." +nation_sanction_help_3: "Lists your nation's Sanctioned Towns." +nation_sanction_help_4: "Lists the given nation's Sanctioned Towns." + king_help_1: 'Nation Leader Help' king_help_2: 'Set your alliance.' king_help_3: 'Set your enemies.' @@ -2371,4 +2376,24 @@ msg_err_resident_is_npc: "You cannot do this to an NPC resident." # Message shown when a resident doesn't own any land and the /res plotlist command is used. msg_err_resident_doesnt_own_any_land: "The resident does not own any land personally." -msg_unnamed: "Unnamed" \ No newline at end of file +msg_unnamed: "Unnamed" + +msg_err_nation_cannot_sanction_own_town: "You cannot sanction a town that is a part of your nation." + +msg_err_nation_town_isnt_sanctioned: "Your nation is not sanctioning that town." + +msg_err_nation_town_already_sanctioned: "Your nation already sanctions that town." + +msg_err_nation_town_sanctioned: "Your nation has now sanctioned %s, they will not be allowed to join your nation." + +msg_err_nation_town_unsanctioned: "Your nation is no longer sanctioning %s." + +msg_err_nation_has_no_sanctioned_towns: "The nation has no sanctioned towns." + +title_nation_sanctioned_towns: 'Sanctioned Towns' + +msg_err_cannot_add_sanctioned_town: "Your nation cannot add %s, your nation has sanctioned them." + +msg_err_cannot_join_nation_sanctioned_town: "Your town cannot join %s, this nation has sanctioned your town." + +msg_err_no_nation_cannot_do: "You cannot perform this action because no nation was able to be determined." \ No newline at end of file diff --git a/Towny/src/main/resources/plugin.yml b/Towny/src/main/resources/plugin.yml index 640db5bc98..4986906125 100644 --- a/Towny/src/main/resources/plugin.yml +++ b/Towny/src/main/resources/plugin.yml @@ -211,6 +211,7 @@ permissions: towny.command.nation.othernation: true towny.command.nation.withdraw: true towny.command.nation.rank.*: true + towny.command.nation.sanctiontown: true towny.command.nation.say: true towny.command.nation.set.*: true towny.command.nation.spawn: true @@ -746,6 +747,7 @@ permissions: towny.command.townyadmin.nation.rank: true towny.command.townyadmin.nation.recheck: true towny.command.townyadmin.nation.rename: true + towny.command.townyadmin.nation.sanctiontown: true towny.command.townyadmin.nation.set: true towny.command.townyadmin.nation.set.*: true towny.command.townyadmin.nation.toggle: true