diff --git a/src/main/java/net/knarcraft/paidsigns/PaidSigns.java b/src/main/java/net/knarcraft/paidsigns/PaidSigns.java index 4a649df..c51c618 100644 --- a/src/main/java/net/knarcraft/paidsigns/PaidSigns.java +++ b/src/main/java/net/knarcraft/paidsigns/PaidSigns.java @@ -174,6 +174,7 @@ public final class PaidSigns extends JavaPlugin { FileConfiguration config = this.getConfig(); config.options().copyDefaults(true); this.saveDefaultConfig(); + this.saveConfig(); ignoreCase = config.getBoolean("ignoreCase", true); ignoreColor = config.getBoolean("ignoreColor", false); enableRefunds = config.getBoolean("enableRefunds", true); @@ -190,7 +191,7 @@ public final class PaidSigns extends JavaPlugin { if (economyProvider != null) { EconomyManager.initialize(economyProvider.getProvider()); } else { - throw new IllegalStateException("[PaidSigns] Error: Vault could not be loaded"); + throw new IllegalStateException("Error: Vault could not be loaded"); } } diff --git a/src/main/java/net/knarcraft/paidsigns/command/AddCommand.java b/src/main/java/net/knarcraft/paidsigns/command/AddCommand.java index eed78d9..82f2fd5 100644 --- a/src/main/java/net/knarcraft/paidsigns/command/AddCommand.java +++ b/src/main/java/net/knarcraft/paidsigns/command/AddCommand.java @@ -11,9 +11,6 @@ import org.bukkit.command.CommandSender; import org.jetbrains.annotations.NotNull; import java.io.IOException; -import java.util.Arrays; -import java.util.logging.Level; -import java.util.logging.Logger; /** * A representation of the command for adding a new paid sign @@ -76,9 +73,6 @@ public class AddCommand extends TokenizedCommand { sender.sendMessage(StringFormatter.getTranslatedInfoMessage(TranslatableMessage.SUCCESS_ADDED_PAID_SIGN)); return true; } catch (IOException e) { - Logger logger = PaidSigns.getInstance().getLogger(); - logger.log(Level.SEVERE, "Exception encountered while trying to write to the data file:"); - logger.log(Level.SEVERE, Arrays.toString(e.getStackTrace())); sender.sendMessage(StringFormatter.getTranslatedErrorMessage(TranslatableMessage.ERROR_EXCEPTION_OCCURRED)); return false; } catch (IllegalArgumentException e) { diff --git a/src/main/java/net/knarcraft/paidsigns/command/AddConditionCommand.java b/src/main/java/net/knarcraft/paidsigns/command/AddConditionCommand.java index 71c9c6b..0ea04fe 100644 --- a/src/main/java/net/knarcraft/paidsigns/command/AddConditionCommand.java +++ b/src/main/java/net/knarcraft/paidsigns/command/AddConditionCommand.java @@ -11,9 +11,6 @@ import org.bukkit.command.CommandSender; import org.jetbrains.annotations.NotNull; import java.io.IOException; -import java.util.Arrays; -import java.util.logging.Level; -import java.util.logging.Logger; /** * A representation of the command for adding a new match condition for a sign @@ -76,9 +73,6 @@ public class AddConditionCommand extends TokenizedCommand { try { signManager.saveSigns(); } catch (IOException e) { - Logger logger = PaidSigns.getInstance().getLogger(); - logger.log(Level.SEVERE, "Exception encountered while trying to write to the data file"); - logger.log(Level.SEVERE, Arrays.toString(e.getStackTrace())); sender.sendMessage(StringFormatter.getTranslatedErrorMessage(TranslatableMessage.ERROR_EXCEPTION_OCCURRED)); return false; } diff --git a/src/main/java/net/knarcraft/paidsigns/command/ReloadTabCommand.java b/src/main/java/net/knarcraft/paidsigns/command/ReloadTabCommand.java index 500efe8..9ed786a 100644 --- a/src/main/java/net/knarcraft/paidsigns/command/ReloadTabCommand.java +++ b/src/main/java/net/knarcraft/paidsigns/command/ReloadTabCommand.java @@ -1,6 +1,8 @@ package net.knarcraft.paidsigns.command; import net.knarcraft.paidsigns.PaidSigns; +import net.knarcraft.paidsigns.formatting.StringFormatter; +import net.knarcraft.paidsigns.formatting.TranslatableMessage; import org.bukkit.command.Command; import org.bukkit.command.CommandSender; import org.bukkit.command.TabExecutor; @@ -18,7 +20,7 @@ public class ReloadTabCommand implements TabExecutor { public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) { PaidSigns.getInstance().reload(); - sender.sendMessage("PaidSigns reloaded"); + sender.sendMessage(StringFormatter.getTranslatedInfoMessage(TranslatableMessage.SUCCESS_RELOADED)); return true; } diff --git a/src/main/java/net/knarcraft/paidsigns/command/RemoveConditionCommand.java b/src/main/java/net/knarcraft/paidsigns/command/RemoveConditionCommand.java index f4b6ada..fc04247 100644 --- a/src/main/java/net/knarcraft/paidsigns/command/RemoveConditionCommand.java +++ b/src/main/java/net/knarcraft/paidsigns/command/RemoveConditionCommand.java @@ -2,15 +2,14 @@ package net.knarcraft.paidsigns.command; import net.knarcraft.paidsigns.PaidSigns; import net.knarcraft.paidsigns.container.PaidSign; +import net.knarcraft.paidsigns.formatting.StringFormatter; +import net.knarcraft.paidsigns.formatting.TranslatableMessage; import net.knarcraft.paidsigns.manager.PaidSignManager; import org.bukkit.command.Command; import org.bukkit.command.CommandSender; import org.jetbrains.annotations.NotNull; import java.io.IOException; -import java.util.Arrays; -import java.util.logging.Level; -import java.util.logging.Logger; /** * A representation of the command for removing a condition from a sign @@ -29,18 +28,19 @@ public class RemoveConditionCommand extends TokenizedCommand { try { line = (short) (Short.parseShort(arguments.get(1)) - 1); } catch (NumberFormatException exception) { - sender.sendMessage("Invalid line number given"); + sender.sendMessage(StringFormatter.getTranslatedErrorMessage(TranslatableMessage.ERROR_INVALID_NUMBER)); return false; } PaidSignManager signManager = PaidSigns.getInstance().getSignManager(); PaidSign sign = signManager.getPaidSign(name); if (sign == null) { - sender.sendMessage("Invalid sign name given"); + sender.sendMessage(StringFormatter.getTranslatedErrorMessage(TranslatableMessage.ERROR_PAID_SIGN_NOT_FOUND)); return false; } if (!sign.getConditions().containsKey(line)) { - sender.sendMessage("No condition registered for line " + (line + 1)); + sender.sendMessage(StringFormatter.replacePlaceholder(StringFormatter.getTranslatedErrorMessage( + TranslatableMessage.ERROR_NO_SUCH_CONDITION), "{line}", String.valueOf((line + 1)))); return false; } @@ -48,13 +48,10 @@ public class RemoveConditionCommand extends TokenizedCommand { try { signManager.saveSigns(); } catch (IOException e) { - Logger logger = PaidSigns.getInstance().getLogger(); - logger.log(Level.SEVERE, "Exception encountered while trying to write to the data file"); - logger.log(Level.SEVERE, Arrays.toString(e.getStackTrace())); - sender.sendMessage("An exception occurred. Please notify the server administrator or check the server log."); + sender.sendMessage(StringFormatter.getTranslatedErrorMessage(TranslatableMessage.ERROR_EXCEPTION_OCCURRED)); return false; } - sender.sendMessage("Condition removed"); + sender.sendMessage(StringFormatter.getTranslatedInfoMessage(TranslatableMessage.SUCCESS_REMOVED_CONDITION)); return true; } diff --git a/src/main/java/net/knarcraft/paidsigns/command/RemoveTabCommand.java b/src/main/java/net/knarcraft/paidsigns/command/RemoveTabCommand.java index 130f2c0..d74f0c7 100644 --- a/src/main/java/net/knarcraft/paidsigns/command/RemoveTabCommand.java +++ b/src/main/java/net/knarcraft/paidsigns/command/RemoveTabCommand.java @@ -2,6 +2,8 @@ package net.knarcraft.paidsigns.command; import net.knarcraft.paidsigns.PaidSigns; import net.knarcraft.paidsigns.container.PaidSign; +import net.knarcraft.paidsigns.formatting.StringFormatter; +import net.knarcraft.paidsigns.formatting.TranslatableMessage; import net.knarcraft.paidsigns.utility.Tokenizer; import org.bukkit.command.Command; import org.bukkit.command.CommandSender; @@ -11,11 +13,8 @@ import org.jetbrains.annotations.Nullable; import java.io.IOException; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; import java.util.Map; -import java.util.logging.Level; -import java.util.logging.Logger; /** * A representation of the command for removing a paid sign @@ -33,17 +32,15 @@ public class RemoveTabCommand implements TabExecutor { try { if (PaidSigns.getInstance().getSignManager().removePaidSign(name)) { - sender.sendMessage("Successfully removed paid sign"); + sender.sendMessage(StringFormatter.getTranslatedInfoMessage( + TranslatableMessage.SUCCESS_REMOVED_PAID_SIGN)); } else { - sender.sendMessage("No matching paid sign was found"); + sender.sendMessage(StringFormatter.getTranslatedErrorMessage( + TranslatableMessage.ERROR_PAID_SIGN_NOT_FOUND)); } return true; } catch (IOException e) { - Logger logger = PaidSigns.getInstance().getLogger(); - logger.log(Level.SEVERE, "Exception encountered while trying to write " + - "to the data file"); - logger.log(Level.SEVERE, Arrays.toString(e.getStackTrace())); - sender.sendMessage("An exception occurred. Please notify the server administrator or check the server log."); + sender.sendMessage(StringFormatter.getTranslatedErrorMessage(TranslatableMessage.ERROR_EXCEPTION_OCCURRED)); } return false; } diff --git a/src/main/java/net/knarcraft/paidsigns/container/PaidSign.java b/src/main/java/net/knarcraft/paidsigns/container/PaidSign.java index 2cc09b2..4b95d58 100644 --- a/src/main/java/net/knarcraft/paidsigns/container/PaidSign.java +++ b/src/main/java/net/knarcraft/paidsigns/container/PaidSign.java @@ -5,6 +5,8 @@ import net.knarcraft.paidsigns.property.OptionState; import java.util.HashMap; import java.util.Map; +import java.util.logging.Level; +import java.util.regex.PatternSyntaxException; /** * A representation of a paid sign @@ -113,7 +115,13 @@ public class PaidSign { for (short i = 0; i < 4; i++) { PaidSignCondition condition = this.conditions.get(i); if (condition != null) { - success = success && condition.test(lines[i]); + try { + success = success && condition.test(lines[i]); + } catch (PatternSyntaxException exception) { + PaidSigns.getInstance().getLogger().log(Level.SEVERE, "The paid sign condition match string:" + + " " + condition.getStringToMatch() + " belonging to sign: " + this.getName() + + " is not a valid regular expression."); + } } } return success; diff --git a/src/main/java/net/knarcraft/paidsigns/formatting/TranslatableMessage.java b/src/main/java/net/knarcraft/paidsigns/formatting/TranslatableMessage.java index 946566b..7a18f34 100644 --- a/src/main/java/net/knarcraft/paidsigns/formatting/TranslatableMessage.java +++ b/src/main/java/net/knarcraft/paidsigns/formatting/TranslatableMessage.java @@ -20,6 +20,31 @@ public enum TranslatableMessage { */ SUCCESS_ADDED_PAID_SIGN_CONDITION, + /** + * The message to display when a paid sign has been successfully removed + */ + SUCCESS_REMOVED_PAID_SIGN, + + /** + * The message to display when a paid sign condition has been successfully removed + */ + SUCCESS_REMOVED_CONDITION, + + /** + * The message to display after the plugin has been reloaded + */ + SUCCESS_RELOADED, + + /** + * The message to display when a player has been charged for creating a paid sign + */ + SUCCESS_PAID_FOR_SIGN, + + /** + * The message to display when a player has been refunded for breaking a sign + */ + SUCCESS_REFUNDED, + /** * The info text used to display all paid signs */ @@ -85,4 +110,9 @@ public enum TranslatableMessage { */ ERROR_NO_SUCH_CONDITION, + /** + * The error to display if a player cannot pay for a sign matching a paid sign + */ + ERROR_CANNOT_AFFORD, + } diff --git a/src/main/java/net/knarcraft/paidsigns/listener/BlockBreakListener.java b/src/main/java/net/knarcraft/paidsigns/listener/BlockBreakListener.java index c7c5eed..f761d21 100644 --- a/src/main/java/net/knarcraft/paidsigns/listener/BlockBreakListener.java +++ b/src/main/java/net/knarcraft/paidsigns/listener/BlockBreakListener.java @@ -1,6 +1,5 @@ package net.knarcraft.paidsigns.listener; -import net.knarcraft.paidsigns.PaidSigns; import net.knarcraft.paidsigns.manager.TrackedSignManager; import org.bukkit.block.Sign; import org.bukkit.event.EventHandler; @@ -9,9 +8,6 @@ import org.bukkit.event.Listener; import org.bukkit.event.block.BlockBreakEvent; import java.io.IOException; -import java.util.Arrays; -import java.util.logging.Level; -import java.util.logging.Logger; /** * A listener that listens for any tracked signs being broken @@ -23,11 +19,7 @@ public class BlockBreakListener implements Listener { if (event.getBlock().getState() instanceof Sign) { try { TrackedSignManager.removeTrackedSign(event.getBlock().getLocation()); - } catch (IOException e) { - e.printStackTrace(); - Logger logger = PaidSigns.getInstance().getLogger(); - logger.log(Level.SEVERE, "Exception encountered while trying to write to the data file"); - logger.log(Level.SEVERE, Arrays.toString(e.getStackTrace())); + } catch (IOException ignored) { } } } diff --git a/src/main/java/net/knarcraft/paidsigns/listener/SignListener.java b/src/main/java/net/knarcraft/paidsigns/listener/SignListener.java index 0ae4c03..40ca086 100644 --- a/src/main/java/net/knarcraft/paidsigns/listener/SignListener.java +++ b/src/main/java/net/knarcraft/paidsigns/listener/SignListener.java @@ -2,6 +2,8 @@ package net.knarcraft.paidsigns.listener; import net.knarcraft.paidsigns.PaidSigns; import net.knarcraft.paidsigns.container.PaidSign; +import net.knarcraft.paidsigns.formatting.StringFormatter; +import net.knarcraft.paidsigns.formatting.TranslatableMessage; import net.knarcraft.paidsigns.manager.EconomyManager; import net.knarcraft.paidsigns.manager.TrackedSignManager; import org.bukkit.entity.Player; @@ -11,10 +13,7 @@ import org.bukkit.event.Listener; import org.bukkit.event.block.SignChangeEvent; import java.io.IOException; -import java.util.Arrays; import java.util.Map; -import java.util.logging.Level; -import java.util.logging.Logger; /** * A listener for listening to registered paid signs @@ -72,19 +71,17 @@ public class SignListener implements Listener { double cost = paidSign.getCost(); boolean canAfford = EconomyManager.canAfford(player, cost); if (!canAfford) { - player.sendMessage("[PaidSigns] You cannot afford to create this sign"); + player.sendMessage(StringFormatter.getTranslatedErrorMessage(TranslatableMessage.ERROR_CANNOT_AFFORD)); event.setCancelled(true); } else { String unit = EconomyManager.getCurrency(cost != 1); - player.sendMessage(String.format("[PaidSigns] You paid %.2f %s to create the sign", cost, unit)); EconomyManager.withdraw(player, cost); + player.sendMessage(String.format(StringFormatter.replacePlaceholders( + StringFormatter.getTranslatedInfoMessage(TranslatableMessage.SUCCESS_PAID_FOR_SIGN), + new String[]{"{cost}", "{unit}"}, new String[]{"%.2f", "%s"}), cost, unit)); try { TrackedSignManager.addTrackedSign(event.getBlock().getLocation(), player.getUniqueId(), cost); - } catch (IOException e) { - e.printStackTrace(); - Logger logger = PaidSigns.getInstance().getLogger(); - logger.log(Level.SEVERE, "Exception encountered while trying to write to the data file"); - logger.log(Level.SEVERE, Arrays.toString(e.getStackTrace())); + } catch (IOException ignored) { } } } diff --git a/src/main/java/net/knarcraft/paidsigns/manager/PaidSignManager.java b/src/main/java/net/knarcraft/paidsigns/manager/PaidSignManager.java index 35c3bba..68972ed 100644 --- a/src/main/java/net/knarcraft/paidsigns/manager/PaidSignManager.java +++ b/src/main/java/net/knarcraft/paidsigns/manager/PaidSignManager.java @@ -9,9 +9,11 @@ import org.bukkit.configuration.file.YamlConfiguration; import java.io.File; import java.io.IOException; +import java.util.Arrays; import java.util.HashMap; import java.util.Map; import java.util.logging.Level; +import java.util.logging.Logger; /** * A manager that keeps track of all registered paid signs @@ -119,26 +121,44 @@ public final class PaidSignManager { * @throws IOException

If unable to write to the signs file

*/ public static void saveSigns(Map signs) throws IOException { - YamlConfiguration configuration = YamlConfiguration.loadConfiguration(signsFile); - ConfigurationSection signSection = configuration.createSection("paidSigns"); + try { + YamlConfiguration configuration = YamlConfiguration.loadConfiguration(signsFile); + ConfigurationSection signSection = configuration.createSection("paidSigns"); - for (PaidSign sign : signs.values()) { - String name = sign.getName(); - signSection.set(name + ".cost", sign.getCost()); - signSection.set(name + ".permission", sign.getPermission()); - signSection.set(name + ".ignoreCase", sign.getIgnoreCase()); - signSection.set(name + ".ignoreColor", sign.getIgnoreColor()); - ConfigurationSection conditionsSection = signSection.createSection(name + ".conditions"); - Map signConditions = sign.getConditions(); - for (short lineIndex : signConditions.keySet()) { - PaidSignCondition condition = signConditions.get(lineIndex); - conditionsSection.set(lineIndex + ".stringToMatch", condition.getStringToMatch()); - conditionsSection.set(lineIndex + ".executeRegEx", condition.executeRegex()); - conditionsSection.set(lineIndex + ".ignoreCase", condition.ignoreCase()); - conditionsSection.set(lineIndex + ".ignoreColor", condition.ignoreColor()); + for (PaidSign sign : signs.values()) { + saveSign(signSection, sign); } + configuration.save(signsFile); + } catch (IOException exception) { + Logger logger = PaidSigns.getInstance().getLogger(); + logger.log(Level.SEVERE, "Exception encountered while trying to write " + + "to the data file"); + logger.log(Level.SEVERE, Arrays.toString(exception.getStackTrace())); + throw exception; + } + } + + /** + * Saves the given sign to the given configuration section + * + * @param signSection

The configuration section to save the sign to

+ * @param sign

The sign to save

+ */ + private static void saveSign(ConfigurationSection signSection, PaidSign sign) { + String name = sign.getName(); + signSection.set(name + ".cost", sign.getCost()); + signSection.set(name + ".permission", sign.getPermission()); + signSection.set(name + ".ignoreCase", sign.getIgnoreCase()); + signSection.set(name + ".ignoreColor", sign.getIgnoreColor()); + ConfigurationSection conditionsSection = signSection.createSection(name + ".conditions"); + Map signConditions = sign.getConditions(); + for (short lineIndex : signConditions.keySet()) { + PaidSignCondition condition = signConditions.get(lineIndex); + conditionsSection.set(lineIndex + ".stringToMatch", condition.getStringToMatch()); + conditionsSection.set(lineIndex + ".executeRegEx", condition.executeRegex()); + conditionsSection.set(lineIndex + ".ignoreCase", condition.ignoreCase()); + conditionsSection.set(lineIndex + ".ignoreColor", condition.ignoreColor()); } - configuration.save(signsFile); } /** diff --git a/src/main/java/net/knarcraft/paidsigns/manager/TrackedSignManager.java b/src/main/java/net/knarcraft/paidsigns/manager/TrackedSignManager.java index ba6df88..c697856 100644 --- a/src/main/java/net/knarcraft/paidsigns/manager/TrackedSignManager.java +++ b/src/main/java/net/knarcraft/paidsigns/manager/TrackedSignManager.java @@ -2,6 +2,8 @@ package net.knarcraft.paidsigns.manager; import net.knarcraft.paidsigns.PaidSigns; import net.knarcraft.paidsigns.container.TrackedSign; +import net.knarcraft.paidsigns.formatting.StringFormatter; +import net.knarcraft.paidsigns.formatting.TranslatableMessage; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.OfflinePlayer; @@ -63,7 +65,10 @@ public final class TrackedSignManager { double refundSum = trackedSign.getCost() / 100 * PaidSigns.getInstance().getRefundPercentage(); EconomyManager.withdraw(offlinePlayer, -refundSum); if (offlinePlayer instanceof Player player) { - player.sendMessage("You were refunded " + refundSum + " for your broken sign"); + player.sendMessage(String.format(StringFormatter.replacePlaceholders( + StringFormatter.getTranslatedInfoMessage(TranslatableMessage.SUCCESS_REFUNDED), + new String[]{"{cost}", "{unit}"}, new String[]{"%.2f", "%s"}), refundSum, + EconomyManager.getCurrency(refundSum != 1))); } } diff --git a/src/main/resources/strings.yml b/src/main/resources/strings.yml index cafed77..e068abf 100644 --- a/src/main/resources/strings.yml +++ b/src/main/resources/strings.yml @@ -2,16 +2,22 @@ en: PREFIX: "[PaidSigns]" SUCCESS_ADDED_PAID_SIGN: "&bSuccessfully added new paid sign" SUCCESS_ADDED_PAID_SIGN_CONDITION: "&bSuccessfully added new paid sign condition" + SUCCESS_REMOVED_PAID_SIGN: "&bSuccessfully removed paid sign" + SUCCESS_REMOVED_CONDITION: "&bSuccessfully removed paid sign condition" + SUCCESS_RELOADED: "&bSuccessfully reloaded configuration" + SUCCESS_PAID_FOR_SIGN: "&bYou paid &3{cost} {unit} &bto create the sign" + SUCCESS_REFUNDED: "&bYou were refunded &3{cost} {unit} &bfor your broken sign" PAID_SIGNS_INFO: "&f---&3Paid signs&f---{signs}\n&f-----------" PAID_SIGNS_INFO_FORMAT: "\n&f| &3{name}" - PAID_SIGN_INFO: "&f---&3Paid sign&f---\n&f| &bName: &3{name}\n&f| &bCost: &3{cost}\n&f| &bPermission: &3{permission}\n&f| &bIgnore case: &3{case}\n&f| &bIgnore color: &3{color}\n&f| &bSign conditions: &3{conditions}\n&f-----------" + PAID_SIGN_INFO: "&f---&3Paid sign&f---\n&f| &bName: &3{name}\n&f| &bCost: &3{cost}\n&f| &bPermission: &3{permission}\n&f| &bIgnore case: &3{case}\n&f| &bIgnore color: &3{color}\n&f| &bSign conditions: &3{conditions}\n&f---------------" PAID_SIGN_INFO_CONDITION_FORMAT: "\n&f| &b{line}: &3{condition}" - PAID_SIGN_CONDITION_INFO: "&f---&3Paid sign condition&f---\n&f| &bPaid sign name: &3{name}\n&f| &bCondition line: &3{line}\n&f| &bMatch string: &3{match}\n&f| &bExecute RegEx: &3{regex}\n&f| &bIgnore case: &3{case}\n&f| &bIgnore color: &3{color}\n-----------" - BOOLEAN_TRUE: "true" - BOOLEAN_FALSE: "false" + PAID_SIGN_CONDITION_INFO: "&f---&3Paid sign condition&f---\n&f| &bPaid sign name: &3{name}\n&f| &bCondition line: &3{line}\n&f| &bMatch string: &3{match}\n&f| &bExecute RegEx: &3{regex}\n&f| &bIgnore case: &3{case}\n&f| &bIgnore color: &3{color}\n&f---------------" + BOOLEAN_TRUE: "&2true" + BOOLEAN_FALSE: "&4false" ERROR_INVALID_NUMBER: "&bYou provided an invalid number" ERROR_NAME_DUPLICATE: "&bA paid sign with the same name already exists" ERROR_EXCEPTION_OCCURRED: "&bAn exception occurred. Please notify the server administrator or check the server log." ERROR_INVALID_INPUT: "&bInvalid input: {input}" ERROR_PAID_SIGN_NOT_FOUND: "&bNo such paid sign exists" - ERROR_NO_SUCH_CONDITION: "&bThe paid sign you specified has no condition for line {line}" \ No newline at end of file + ERROR_NO_SUCH_CONDITION: "&bThe paid sign you specified has no condition for line {line}" + ERROR_CANNOT_AFFORD: "&bYou cannot afford to create this sign" \ No newline at end of file