diff --git a/CHANGELOG.md b/CHANGELOG.md index fa97fcbe..f3e10139 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -90,6 +90,21 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `ESSENTIALS_BACK` zone flag — controls whether /back teleportation works in zones (defaults to allowed) - `FactionHomeTeleportEvent` and `FactionHomeTeleportPreEvent` events for home teleport tracking +**Per-World Max Claims** +- New `maxClaims` per-world setting in `worlds.json` — limits how many claims a single faction can hold in a specific world +- `null` or `0` = use global limit, `>0` = per-faction per-world hard cap +- Enforced in both `/f claim` and `/f overclaim` flows +- Admin commands: `/f admin world set maxclaims `, supports `default`/`0` to clear +- New `WORLD_MAX_CLAIMS_REACHED` claim result handled in all consumer sites (commands, GUI map, dashboard) +- Localized error messages in all 10 locales + +**World Settings API** +- `HyperFactionsAPI.registerWorldSettings(worldKey, settings)` — upsert with persistence, thread-safe +- `HyperFactionsAPI.getWorldSettings(worldName)` — resolved through wildcard pattern matching +- `HyperFactionsAPI.getConfiguredWorldSettings(worldKey)` — exact key match, no pattern resolution +- `HyperFactionsAPI.removeWorldSettings(worldKey)` — removes and persists +- `WorldSettingsResolver` made thread-safe with volatile fields and copy-on-write rebuild + ### Changed **Consolidate Duplicate Message Keys** diff --git a/docs/api.md b/docs/api.md index af834b44..a4ce624d 100644 --- a/docs/api.md +++ b/docs/api.md @@ -18,6 +18,7 @@ This document is for third-party mod developers who want to hook into HyperFacti - [Protection](#protection) - [Language / i18n](#language--i18n) - [Chat Color Customization](#chat-color-customization) +- [World Settings](#world-settings) - [Configuration](#configuration) - [Manager Access](#manager-access) - [Economy API](#economy-api) @@ -349,6 +350,60 @@ HyperFactionsAPI.setChatColors(originalColors); --- +## World Settings + +Manage per-world behavior overrides at runtime. Other plugins can register, query, and remove world settings programmatically. Changes are persisted to `worlds.json` immediately. + +### Methods + +| Method | Returns | Description | +|--------|---------|-------------| +| `registerWorldSettings(String worldKey, WorldsConfig.WorldSettings settings)` | `void` | Upsert world settings — creates or replaces the entry for `worldKey`, persists to disk. Thread-safe. | +| `getWorldSettings(String worldName)` | `@Nullable WorldsConfig.WorldSettings` | Resolve settings for a world name, including wildcard pattern matching (exact match > wildcards > null). | +| `getConfiguredWorldSettings(String worldKey)` | `@Nullable WorldsConfig.WorldSettings` | Get settings for an exact key only (no pattern matching). Returns null if the key is not configured. | +| `removeWorldSettings(String worldKey)` | `void` | Remove the entry for `worldKey` and persist the change. No-op if key does not exist. | + +### WorldSettings Record + +`WorldsConfig.WorldSettings` is a record with 5 fields. Any field set to `null` inherits from global config: + +```java +record WorldSettings( + @Nullable Boolean claiming, // Allow claiming in this world + @Nullable Boolean powerLoss, // Apply power loss in this world + @Nullable Boolean friendlyFireFaction, // Same-faction PvP override + @Nullable Boolean friendlyFireAlly, // Ally PvP override + @Nullable Integer maxClaims // Per-faction claim cap (null/0 = use global) +) +``` + +### Example + +```java +// Register world settings from another mod +WorldsConfig.WorldSettings eventSettings = new WorldsConfig.WorldSettings( + true, // claiming allowed + false, // no power loss + null, // faction FF: use global + null, // ally FF: use global + 5 // max 5 claims per faction +); +HyperFactionsAPI.registerWorldSettings("events", eventSettings); + +// Query resolved settings (includes pattern matching) +WorldsConfig.WorldSettings resolved = HyperFactionsAPI.getWorldSettings("events"); + +// Query exact key only (no pattern matching) +WorldsConfig.WorldSettings exact = HyperFactionsAPI.getConfiguredWorldSettings("events"); + +// Remove settings +HyperFactionsAPI.removeWorldSettings("events"); +``` + +> **Note:** `registerWorldSettings()` uses upsert semantics — if the key already exists, the entry is replaced. All mutations are thread-safe and persisted to `worlds.json` immediately. + +--- + ## Configuration | Method | Description | diff --git a/docs/commands.md b/docs/commands.md index a894d19a..fd373b0b 100644 --- a/docs/commands.md +++ b/docs/commands.md @@ -370,7 +370,9 @@ Admin commands use nested subcommand structure: ├── world # Per-world settings management │ ├── list # List all world overrides │ ├── info # Show settings for a world -│ ├── set # Set a per-world setting +│ ├── set # Set a per-world setting (keys: claiming, powerLoss, friendlyFireFaction, friendlyFireAlly, maxClaims) +│ │ # maxClaims takes an integer (e.g., /f admin world set events maxClaims 5) +│ │ # Use "maxClaims default" or "maxClaims 0" to clear per-world limit (inherit global) │ └── reset # Reset world to defaults ├── economy # Economy management │ └── upkeep # Upkeep system control diff --git a/docs/config.md b/docs/config.md index 4e2f81a2..08ed1e55 100644 --- a/docs/config.md +++ b/docs/config.md @@ -330,7 +330,7 @@ Territory settings: | Key | Type | Default | Description | |-----|------|---------|-------------| -| `maxClaims` | int | 100 | Hard limit per faction | +| `maxClaims` | int | 100 | Global hard limit per faction (can be overridden per-world via `worlds.json`) | | `onlyAdjacent` | bool | false | Require adjacent claims | | `decayEnabled` | bool | true | Enable claim decay | | `decayDaysInactive` | int | 30 | Days before decay starts | @@ -564,7 +564,7 @@ Per-world behavior overrides in `config/worlds.json`: | `claimBlacklist` | array | [] | Worlds where claiming is unconditionally blocked | | `worlds` | object | `{}` | Per-world setting overrides (keyed by world name or wildcard pattern) | -Per-world settings (4 per entry): +Per-world settings (5 per entry): | Key | Type | Default | Description | |-----|------|---------|-------------| @@ -572,6 +572,7 @@ Per-world settings (4 per entry): | `powerLoss` | bool | true | Whether power loss applies in this world | | `friendlyFireFaction` | bool | *(from global config)* | Same-faction PvP override | | `friendlyFireAlly` | bool | *(from global config)* | Ally PvP override | +| `maxClaims` | Integer | null | Maximum claims a faction can hold in this world. `null` or `0` = use global limit, `>0` = per-faction per-world hard cap | **Wildcard support**: Use `%` as a wildcard in world names (e.g., `arena_%` matches `arena_1`, `arena_pvp`). Priority resolution: exact name match > wildcard patterns (fewer wildcards = higher priority) > default policy. @@ -584,7 +585,8 @@ Per-world settings (4 per entry): "claimBlacklist": ["lobby"], "worlds": { "arena_%": { "claiming": false, "powerLoss": false }, - "instance-%": { "claiming": false } + "instance-%": { "claiming": false }, + "events": { "claiming": true, "powerLoss": false, "maxClaims": 5 } } } ``` diff --git a/docs/managers.md b/docs/managers.md index 28562130..4df1a75d 100644 --- a/docs/managers.md +++ b/docs/managers.md @@ -198,6 +198,7 @@ Territory claiming and chunk ownership tracking. | `overclaim(playerUuid, world, chunkX, chunkZ)` | `territory.overclaim` | `ClaimResult` | | `getClaimOwner(world, chunkX, chunkZ)` | - | `UUID` (factionId) | | `getClaimCount(factionId)` | - | `int` | +| `countFactionClaimsInWorld(factionId, world)` | - | `int` | | `getFactionClaims(factionId)` | - | `List` | ### Result Enum @@ -212,6 +213,7 @@ public enum ClaimResult { ALREADY_YOURS, INSUFFICIENT_POWER, MAX_CLAIMS_REACHED, + WORLD_MAX_CLAIMS_REACHED, ADJACENT_REQUIRED, WORLD_BLACKLISTED, NOT_IN_WHITELIST, @@ -220,6 +222,8 @@ public enum ClaimResult { } ``` +`WORLD_MAX_CLAIMS_REACHED` is returned when the faction has hit the per-world claim cap configured in `worlds.json` (the `maxClaims` setting). This is checked in both the `claim()` and `overclaim()` flows using the `countFactionClaimsInWorld()` helper, which counts existing claims for a faction in a specific world. + ### Debounce Claim and unclaim operations have a 500ms per-player debounce to prevent double-execution from rapid command dispatch or key-down/key-up events. diff --git a/src/main/java/com/hyperfactions/api/HyperFactionsAPI.java b/src/main/java/com/hyperfactions/api/HyperFactionsAPI.java index 0aa3b79a..94d07c66 100644 --- a/src/main/java/com/hyperfactions/api/HyperFactionsAPI.java +++ b/src/main/java/com/hyperfactions/api/HyperFactionsAPI.java @@ -812,6 +812,59 @@ public static Set getFactionClaims(@NotNull UUID factionId) { return getInstance().getClaimManager().getFactionClaims(factionId); } + // === World Settings === + + /** + * Registers or updates per-world settings for the given world key. + * Upsert semantics: skips save if settings are identical to existing. + * Settings are persisted to worlds.json immediately. + * Thread-safe — can be called from any thread. + * + * @param worldKey the world name or wildcard pattern (e.g., "events", "instance_%") + * @param settings the settings to apply (null fields = inherit from global config) + */ + public static void registerWorldSettings(@NotNull String worldKey, + @NotNull com.hyperfactions.config.modules.WorldsConfig.WorldSettings settings) { + ConfigManager.get().registerWorldSettings(worldKey, settings); + } + + /** + * Gets the resolved settings for a world (through pattern matching). + * Returns null if no specific settings exist for this world. + * + * @param worldName the world name + * @return resolved settings, or null for default policy + */ + @Nullable + public static com.hyperfactions.config.modules.WorldsConfig.WorldSettings getWorldSettings( + @NotNull String worldName) { + return ConfigManager.get().getWorldSettingsResolver().resolve(worldName); + } + + /** + * Gets the raw configured settings for an exact world key. + * Does NOT do pattern matching — returns settings only if the exact key exists. + * + * @param worldKey the exact world key + * @return the settings, or null if not configured + */ + @Nullable + public static com.hyperfactions.config.modules.WorldsConfig.WorldSettings getConfiguredWorldSettings( + @NotNull String worldKey) { + return ConfigManager.get().worlds().getWorldSettings(worldKey); + } + + /** + * Removes per-world settings for the given key and persists. + * Thread-safe. + * + * @param worldKey the world key to remove + * @return true if settings were removed + */ + public static boolean removeWorldSettings(@NotNull String worldKey) { + return ConfigManager.get().removeExternalWorldSettings(worldKey); + } + // === Configuration === /** diff --git a/src/main/java/com/hyperfactions/command/admin/handler/AdminWorldHandler.java b/src/main/java/com/hyperfactions/command/admin/handler/AdminWorldHandler.java index eb53277c..dd8f1dbd 100644 --- a/src/main/java/com/hyperfactions/command/admin/handler/AdminWorldHandler.java +++ b/src/main/java/com/hyperfactions/command/admin/handler/AdminWorldHandler.java @@ -130,6 +130,9 @@ private void handleList(CommandContext ctx, @Nullable PlayerRef player) { if (settings.friendlyFireAlly() != null) { parts.add("ffAlly=" + boolStr(settings.friendlyFireAlly())); } + if (settings.maxClaims() != null && settings.maxClaims() > 0) { + parts.add("maxClaims=" + settings.maxClaims()); + } if (parts.isEmpty()) { line = line.insert(msg("(no overrides)", COLOR_GRAY)); @@ -167,6 +170,8 @@ private void handleInfo(CommandContext ctx, String[] args) { ctx.sendMessage(msg(" Power loss: " + boolStr(powerLoss), COLOR_WHITE)); ctx.sendMessage(msg(" Faction FF: " + (ffFaction != null ? boolStr(ffFaction) : "global (" + boolStr(config.isFactionDamage()) + ")"), COLOR_WHITE)); ctx.sendMessage(msg(" Ally FF: " + (ffAlly != null ? boolStr(ffAlly) : "global (" + boolStr(config.isAllyDamage()) + ")"), COLOR_WHITE)); + Integer maxClaims = resolved != null ? resolved.maxClaims() : null; + ctx.sendMessage(msg(" Max claims: " + (maxClaims != null && maxClaims > 0 ? maxClaims : "unlimited (global)"), COLOR_WHITE)); if (resolved != null) { ctx.sendMessage(msg(" Source: per-world override", COLOR_GRAY)); @@ -181,8 +186,8 @@ private void handleInfo(CommandContext ctx, String[] args) { */ private void handleSet(CommandContext ctx, @Nullable PlayerRef player, String[] args) { if (args.length < 3) { - ctx.sendMessage(prefix().insert(msg("Usage: /f admin world set ", COLOR_RED))); - ctx.sendMessage(msg(" Settings: claiming, powerLoss, friendlyFireFaction, friendlyFireAlly", COLOR_GRAY)); + ctx.sendMessage(prefix().insert(msg("Usage: /f admin world set ", COLOR_RED))); + ctx.sendMessage(msg(" Settings: claiming, powerLoss, friendlyFireFaction, friendlyFireAlly, maxClaims", COLOR_GRAY)); return; } @@ -190,6 +195,41 @@ private void handleSet(CommandContext ctx, @Nullable PlayerRef player, String[] String setting = args[1].toLowerCase(); String valueStr = args[2].toLowerCase(); + // Handle integer settings + if (setting.equals("maxclaims")) { + WorldsConfig config = ConfigManager.get().worlds(); + WorldSettings current = config.getWorldSettings(worldKey); + if (current == null) { + current = WorldSettings.DEFAULTS; + } + + Integer maxClaimsVal; + if (valueStr.equals("default") || valueStr.equals("null") || valueStr.equals("0")) { + maxClaimsVal = null; + } else { + try { + maxClaimsVal = Integer.parseInt(valueStr); + } catch (NumberFormatException e) { + ctx.sendMessage(prefix().insert(msg("maxClaims must be a number, 'default', or '0'.", COLOR_RED))); + return; + } + if (maxClaimsVal < 0) { + ctx.sendMessage(prefix().insert(msg("maxClaims cannot be negative.", COLOR_RED))); + return; + } + } + + WorldSettings updated = new WorldSettings(current.claiming(), current.powerLoss(), + current.friendlyFireFaction(), current.friendlyFireAlly(), maxClaimsVal); + config.setWorldSettings(worldKey, updated); + config.save(); + ConfigManager.get().getWorldSettingsResolver().rebuild(config); + + String displayVal = maxClaimsVal != null ? String.valueOf(maxClaimsVal) : "unlimited"; + ctx.sendMessage(prefix().insert(msg(HFMessages.get(player, AdminKeys.AdminCmd.WORLD_SET, "maxClaims", displayVal, worldKey), COLOR_GREEN))); + return; + } + if (!valueStr.equals("true") && !valueStr.equals("false")) { ctx.sendMessage(prefix().insert(msg("Value must be 'true' or 'false'.", COLOR_RED))); return; @@ -203,13 +243,13 @@ private void handleSet(CommandContext ctx, @Nullable PlayerRef player, String[] } WorldSettings updated = switch (setting) { - case "claiming" -> new WorldSettings(value, current.powerLoss(), current.friendlyFireFaction(), current.friendlyFireAlly()); - case "powerloss" -> new WorldSettings(current.claiming(), value, current.friendlyFireFaction(), current.friendlyFireAlly()); - case "friendlyfirefaction", "fffaction" -> new WorldSettings(current.claiming(), current.powerLoss(), value, current.friendlyFireAlly()); - case "friendlyfireally", "ffally" -> new WorldSettings(current.claiming(), current.powerLoss(), current.friendlyFireFaction(), value); + case "claiming" -> new WorldSettings(value, current.powerLoss(), current.friendlyFireFaction(), current.friendlyFireAlly(), current.maxClaims()); + case "powerloss" -> new WorldSettings(current.claiming(), value, current.friendlyFireFaction(), current.friendlyFireAlly(), current.maxClaims()); + case "friendlyfirefaction", "fffaction" -> new WorldSettings(current.claiming(), current.powerLoss(), value, current.friendlyFireAlly(), current.maxClaims()); + case "friendlyfireally", "ffally" -> new WorldSettings(current.claiming(), current.powerLoss(), current.friendlyFireFaction(), value, current.maxClaims()); default -> { ctx.sendMessage(prefix().insert(msg(HFMessages.get(player, AdminKeys.AdminCmd.WORLD_UNKNOWN_SETTING, setting), COLOR_RED))); - ctx.sendMessage(msg(" Settings: claiming, powerLoss, friendlyFireFaction, friendlyFireAlly", COLOR_GRAY)); + ctx.sendMessage(msg(" Settings: claiming, powerLoss, friendlyFireFaction, friendlyFireAlly, maxClaims", COLOR_GRAY)); yield null; } }; diff --git a/src/main/java/com/hyperfactions/command/territory/ClaimSubCommand.java b/src/main/java/com/hyperfactions/command/territory/ClaimSubCommand.java index bd289fef..251b4fef 100644 --- a/src/main/java/com/hyperfactions/command/territory/ClaimSubCommand.java +++ b/src/main/java/com/hyperfactions/command/territory/ClaimSubCommand.java @@ -2,6 +2,7 @@ import com.hyperfactions.HyperFactions; import com.hyperfactions.Permissions; +import com.hyperfactions.config.ConfigManager; import com.hyperfactions.command.FactionCommandContext; import com.hyperfactions.command.FactionSubCommand; import com.hyperfactions.command.util.CommandUtil; @@ -115,6 +116,10 @@ protected void execute(@NotNull CommandContext ctx, case ALREADY_CLAIMED_SELF -> ctx.sendMessage(MessageUtil.error(player, CommandKeys.Claim.ALREADY_YOURS)); case ALREADY_CLAIMED_OTHER -> ctx.sendMessage(MessageUtil.error(player, CommandKeys.Claim.ALREADY_CLAIMED)); case MAX_CLAIMS_REACHED -> ctx.sendMessage(MessageUtil.error(player, CommandKeys.Claim.MAX_CLAIMS)); + case WORLD_MAX_CLAIMS_REACHED -> { + Integer wmc = ConfigManager.get().getWorldMaxClaims(currentWorld.getName()); + ctx.sendMessage(MessageUtil.error(player, CommandKeys.Claim.WORLD_MAX_CLAIMS, wmc != null ? wmc : "?")); + } case NOT_ADJACENT -> ctx.sendMessage(MessageUtil.error(player, CommandKeys.Claim.NOT_CONNECTED)); case WORLD_NOT_ALLOWED -> ctx.sendMessage(MessageUtil.error(player, CommandKeys.Claim.WORLD_NOT_ALLOWED)); case ORBISGUARD_PROTECTED -> ctx.sendMessage(MessageUtil.error(player, CommandKeys.Claim.ORBISGUARD)); diff --git a/src/main/java/com/hyperfactions/command/territory/OverclaimSubCommand.java b/src/main/java/com/hyperfactions/command/territory/OverclaimSubCommand.java index 5c84c00a..099fa986 100644 --- a/src/main/java/com/hyperfactions/command/territory/OverclaimSubCommand.java +++ b/src/main/java/com/hyperfactions/command/territory/OverclaimSubCommand.java @@ -2,6 +2,7 @@ import com.hyperfactions.HyperFactions; import com.hyperfactions.Permissions; +import com.hyperfactions.config.ConfigManager; import com.hyperfactions.command.FactionCommandContext; import com.hyperfactions.command.FactionSubCommand; import com.hyperfactions.command.util.CommandUtil; @@ -86,6 +87,10 @@ protected void execute(@NotNull CommandContext ctx, case ALREADY_CLAIMED_ALLY -> ctx.sendMessage(MessageUtil.error(player, CommandKeys.Claim.OVERCLAIM_ALLY)); case TARGET_HAS_POWER -> ctx.sendMessage(MessageUtil.error(player, CommandKeys.Claim.TARGET_HAS_POWER)); case MAX_CLAIMS_REACHED -> ctx.sendMessage(MessageUtil.error(player, CommandKeys.Claim.MAX_CLAIMS)); + case WORLD_MAX_CLAIMS_REACHED -> { + Integer wmc = ConfigManager.get().getWorldMaxClaims(currentWorld.getName()); + ctx.sendMessage(MessageUtil.error(player, CommandKeys.Claim.WORLD_MAX_CLAIMS, wmc != null ? wmc : "?")); + } default -> ctx.sendMessage(MessageUtil.error(player, CommandKeys.Claim.OVERCLAIM_FAILED)); } } diff --git a/src/main/java/com/hyperfactions/config/ConfigManager.java b/src/main/java/com/hyperfactions/config/ConfigManager.java index 750e47b2..9e6b72f2 100644 --- a/src/main/java/com/hyperfactions/config/ConfigManager.java +++ b/src/main/java/com/hyperfactions/config/ConfigManager.java @@ -52,6 +52,8 @@ public class ConfigManager { private final WorldSettingsResolver worldSettingsResolver = new WorldSettingsResolver(); + private final Object worldSettingsLock = new Object(); + private ConfigManager() {} /** @@ -676,6 +678,27 @@ public boolean isPowerLossEnabledInWorld(@NotNull String worldName) { return true; } + /** + * Gets the per-world max claims limit for a world. + * Returns null if no per-world limit is set (use global config). + * + * @param worldName the world name + * @return the max claims limit, or null for no per-world limit + */ + @org.jetbrains.annotations.Nullable + public Integer getWorldMaxClaims(@NotNull String worldName) { + if (worldsConfig != null && worldsConfig.isEnabled()) { + return worldSettingsResolver.getMaxClaimsInWorld(worldName); + } + return null; + } + + /** Returns the worlds config, or null if not loaded. */ + @org.jetbrains.annotations.Nullable + public WorldsConfig getWorldsConfig() { + return worldsConfig; + } + // Combat (from factions config) /** Returns the tag duration seconds. */ public int getTagDurationSeconds() { @@ -1319,4 +1342,41 @@ public boolean isAllowWithoutPermissionMod() { public boolean isPermissionLocked(@NotNull String permissionName) { return factionPermissionsConfig.isPermissionLocked(permissionName); } + + // === World Settings API === + + /** + * Registers or updates per-world settings for the given world key. + * Upsert semantics: skips save if settings are identical to existing. + * Thread-safe. + * + * @param worldKey the world name or wildcard pattern + * @param settings the settings to apply + */ + public void registerWorldSettings(@NotNull String worldKey, + @NotNull com.hyperfactions.config.modules.WorldsConfig.WorldSettings settings) { + synchronized (worldSettingsLock) { + com.hyperfactions.config.modules.WorldsConfig.WorldSettings existing = worldsConfig.getWorldSettings(worldKey); + if (settings.equals(existing)) return; + worldsConfig.setWorldSettings(worldKey, settings); + worldsConfig.save(); + worldSettingsResolver.rebuild(worldsConfig); + } + } + + /** + * Removes per-world settings for the given key and persists. + * Thread-safe. + * + * @param worldKey the world key to remove + * @return true if settings were removed + */ + public boolean removeExternalWorldSettings(@NotNull String worldKey) { + synchronized (worldSettingsLock) { + if (!worldsConfig.removeWorldSettings(worldKey)) return false; + worldsConfig.save(); + worldSettingsResolver.rebuild(worldsConfig); + return true; + } + } } diff --git a/src/main/java/com/hyperfactions/config/WorldSettingsResolver.java b/src/main/java/com/hyperfactions/config/WorldSettingsResolver.java index f606c02b..f31efb9a 100644 --- a/src/main/java/com/hyperfactions/config/WorldSettingsResolver.java +++ b/src/main/java/com/hyperfactions/config/WorldSettingsResolver.java @@ -26,13 +26,13 @@ public class WorldSettingsResolver { /** Cached compiled patterns for wildcard world keys. */ - private final List wildcardPatterns = new ArrayList<>(); + private volatile List wildcardPatterns = List.of(); /** Exact-match world settings. */ - private final Map exactMatches = new HashMap<>(); + private volatile Map exactMatches = Map.of(); /** The default policy when no match is found. */ - private boolean defaultAllow = true; + private volatile boolean defaultAllow = true; // claimBlacklist removed in v8 — migrated to per-world claiming=false entries @@ -46,31 +46,32 @@ private record WildcardEntry(String key, Pattern pattern, int wildcardCount, Wor * @param config the worlds config */ public void rebuild(@NotNull WorldsConfig config) { - exactMatches.clear(); - wildcardPatterns.clear(); - defaultAllow = "allow".equals(config.getDefaultPolicy()); + Map newExact = new HashMap<>(); + List newWild = new ArrayList<>(); + boolean newDefaultAllow = "allow".equals(config.getDefaultPolicy()); for (Map.Entry entry : config.getWorlds().entrySet()) { String key = entry.getKey(); if (key.contains("%")) { - // Wildcard pattern String regex = Pattern.quote(key).replace("%", "\\E.*\\Q"); - // Clean up empty quote groups regex = regex.replace("\\Q\\E", ""); Pattern pattern = Pattern.compile("^" + regex + "$"); int wildcardCount = (int) key.chars().filter(c -> c == '%').count(); - wildcardPatterns.add(new WildcardEntry(key, pattern, wildcardCount, entry.getValue())); + newWild.add(new WildcardEntry(key, pattern, wildcardCount, entry.getValue())); } else { - // Exact match - exactMatches.put(key, entry.getValue()); + newExact.put(key, entry.getValue()); } } - // Sort wildcards: fewer wildcards = higher priority (more specific) - wildcardPatterns.sort(Comparator.comparingInt(WildcardEntry::wildcardCount)); + newWild.sort(Comparator.comparingInt(WildcardEntry::wildcardCount)); + + // Atomic swap (volatile writes) + this.wildcardPatterns = List.copyOf(newWild); + this.exactMatches = Map.copyOf(newExact); + this.defaultAllow = newDefaultAllow; Logger.debug("[Worlds] Resolver rebuilt: %d exact, %d wildcard, defaultAllow=%s", - exactMatches.size(), wildcardPatterns.size(), defaultAllow); + newExact.size(), newWild.size(), newDefaultAllow); } /** @@ -164,6 +165,22 @@ public Boolean isFriendlyFireAllyAllowed(@NotNull String worldName) { return null; // Caller uses global config } + /** + * Gets the per-world max claims limit for a world. + * Returns null if no per-world limit is set (use global config). + * + * @param worldName the world name + * @return the max claims limit, or null for no per-world limit + */ + @Nullable + public Integer getMaxClaimsInWorld(@NotNull String worldName) { + WorldSettings settings = resolve(worldName); + if (settings != null && settings.maxClaims() != null && settings.maxClaims() > 0) { + return settings.maxClaims(); + } + return null; + } + /** * Checks if the default policy is "allow". * diff --git a/src/main/java/com/hyperfactions/config/modules/WorldsConfig.java b/src/main/java/com/hyperfactions/config/modules/WorldsConfig.java index 0ceae783..fd651db0 100644 --- a/src/main/java/com/hyperfactions/config/modules/WorldsConfig.java +++ b/src/main/java/com/hyperfactions/config/modules/WorldsConfig.java @@ -37,15 +37,17 @@ public class WorldsConfig extends ModuleConfig { * @param powerLoss whether power loss on death applies (null = use default) * @param friendlyFireFaction whether faction-on-faction friendly fire is allowed (null = use default) * @param friendlyFireAlly whether ally-on-ally friendly fire is allowed (null = use default) + * @param maxClaims per-world max claims limit (null/0 = use global limit) */ public record WorldSettings( Boolean claiming, Boolean powerLoss, Boolean friendlyFireFaction, - Boolean friendlyFireAlly + Boolean friendlyFireAlly, + Integer maxClaims ) { /** Default settings — all null means defer to global config. */ - public static final WorldSettings DEFAULTS = new WorldSettings(null, null, null, null); + public static final WorldSettings DEFAULTS = new WorldSettings(null, null, null, null, null); } private String defaultPolicy = "allow"; @@ -73,9 +75,9 @@ protected void createDefaults() { defaultPolicy = "allow"; worlds.clear(); // Block claiming in temporary instance worlds (power loss defers to global config) - worlds.put("instance-%", new WorldSettings(false, null, null, null)); + worlds.put("instance-%", new WorldSettings(false, null, null, null, null)); // Example entry showing all available options (non-matching name won't affect real worlds) - worlds.put("example-world-abc", new WorldSettings(true, true, false, false)); + worlds.put("example-world-abc", new WorldSettings(true, true, false, false, null)); } /** Loads module settings. */ @@ -93,7 +95,8 @@ protected void loadModuleSettings(@NotNull JsonObject root) { getNullableBool(worldObj, "claiming"), getNullableBool(worldObj, "powerLoss"), getNullableBool(worldObj, "friendlyFireFaction"), - getNullableBool(worldObj, "friendlyFireAlly") + getNullableBool(worldObj, "friendlyFireAlly"), + getNullableInt(worldObj, "maxClaims") ); worlds.put(entry.getKey(), settings); } @@ -122,6 +125,9 @@ protected void writeModuleSettings(@NotNull JsonObject root) { if (s.friendlyFireAlly() != null) { worldObj.addProperty("friendlyFireAlly", s.friendlyFireAlly()); } + if (s.maxClaims() != null && s.maxClaims() > 0) { + worldObj.addProperty("maxClaims", s.maxClaims()); + } worldsObj.add(entry.getKey(), worldObj); } root.add("worlds", worldsObj); @@ -189,6 +195,16 @@ public ValidationResult validate() { defaultPolicy = "allow"; } + for (Map.Entry entry : worlds.entrySet()) { + WorldSettings ws = entry.getValue(); + if (ws.maxClaims() != null && ws.maxClaims() < 0) { + result.addWarning("worlds", entry.getKey() + ".maxClaims", + "must be >= 0", ws.maxClaims(), null); + worlds.put(entry.getKey(), new WorldSettings(ws.claiming(), ws.powerLoss(), + ws.friendlyFireFaction(), ws.friendlyFireAlly(), null)); + } + } + return result; } @@ -204,4 +220,15 @@ private Boolean getNullableBool(@NotNull JsonObject obj, @NotNull String key) { } return null; } + + /** + * Gets a nullable Integer from a JSON object. + * Returns null if the key doesn't exist or is null. + */ + private Integer getNullableInt(@NotNull JsonObject obj, @NotNull String key) { + if (obj.has(key) && !obj.get(key).isJsonNull()) { + return obj.get(key).getAsInt(); + } + return null; + } } diff --git a/src/main/java/com/hyperfactions/gui/admin/page/AdminConfigPage.java b/src/main/java/com/hyperfactions/gui/admin/page/AdminConfigPage.java index a7e3e2eb..92f99c05 100644 --- a/src/main/java/com/hyperfactions/gui/admin/page/AdminConfigPage.java +++ b/src/main/java/com/hyperfactions/gui/admin/page/AdminConfigPage.java @@ -958,6 +958,23 @@ private void addWorldOverrideEntry(UICommandBuilder cmd, UIEventBuilder events, EventData.of("Button", "WorldSettingChanged").append("SettingKey", settingKey) .append("@enumValue", settingIdx + " #TristateSelect.Value"), false); } + + // Max Claims (integer setting — 0 = use global limit) + String maxClaimsKey = "worlds.override." + worldKey + ".maxClaims"; + int maxClaimsVal = ws.maxClaims() != null ? ws.maxClaims() : 0; + String settingsContainer = idx + " #WorldSettings"; + cmd.append(settingsContainer, UIPaths.ADMIN_CONFIG_NUM_ROW); + String mcIdx = settingsContainer + "[" + settings.length + "]"; + cmd.set(mcIdx + " #SettingLabel.Text", "Max Claims"); + cmd.set(mcIdx + " #SettingLabel.Style.TextColor", "#CCCCCC"); + cmd.set(mcIdx + " #NumInput.Value", String.valueOf(maxClaimsVal)); + events.addEventBinding(CustomUIEventBindingType.Activating, mcIdx + " #DecBtn", + EventData.of("Button", "WorldMaxClaimsDec").append("SettingKey", maxClaimsKey), false); + events.addEventBinding(CustomUIEventBindingType.Activating, mcIdx + " #IncBtn", + EventData.of("Button", "WorldMaxClaimsInc").append("SettingKey", maxClaimsKey), false); + events.addEventBinding(CustomUIEventBindingType.ValueChanged, mcIdx + " #NumInput", + EventData.of("Button", "WorldMaxClaimsInput").append("SettingKey", maxClaimsKey) + .append("@numInput", mcIdx + " #NumInput.Value"), false); } incrementRowIdx(); @@ -1443,6 +1460,27 @@ public void handleDataEvent(Ref ref, Store store, } } + case "WorldMaxClaimsInc" -> { + if (data.settingKey != null) { + handleWorldMaxClaimsIncrement(data.settingKey, true); + refresh(ref, store); + } + } + + case "WorldMaxClaimsDec" -> { + if (data.settingKey != null) { + handleWorldMaxClaimsIncrement(data.settingKey, false); + refresh(ref, store); + } + } + + case "WorldMaxClaimsInput" -> { + if (data.settingKey != null && data.numInput != null) { + handleWorldMaxClaimsInput(data.settingKey, data.numInput); + refresh(ref, store); + } + } + case "Save" -> { if (!invalidFields.isEmpty()) { // Can't save with invalid fields @@ -1644,15 +1682,56 @@ private void handleWorldSettingChanged(String key, String value) { WorldsConfig.WorldSettings current = overrides.getOrDefault(worldKey, WorldsConfig.WorldSettings.DEFAULTS); Boolean val = triStateFromString(value); WorldsConfig.WorldSettings updated = switch (setting) { - case "claiming" -> new WorldsConfig.WorldSettings(val, current.powerLoss(), current.friendlyFireFaction(), current.friendlyFireAlly()); - case "powerLoss" -> new WorldsConfig.WorldSettings(current.claiming(), val, current.friendlyFireFaction(), current.friendlyFireAlly()); - case "friendlyFireFaction" -> new WorldsConfig.WorldSettings(current.claiming(), current.powerLoss(), val, current.friendlyFireAlly()); - case "friendlyFireAlly" -> new WorldsConfig.WorldSettings(current.claiming(), current.powerLoss(), current.friendlyFireFaction(), val); + case "claiming" -> new WorldsConfig.WorldSettings(val, current.powerLoss(), current.friendlyFireFaction(), current.friendlyFireAlly(), current.maxClaims()); + case "powerLoss" -> new WorldsConfig.WorldSettings(current.claiming(), val, current.friendlyFireFaction(), current.friendlyFireAlly(), current.maxClaims()); + case "friendlyFireFaction" -> new WorldsConfig.WorldSettings(current.claiming(), current.powerLoss(), val, current.friendlyFireAlly(), current.maxClaims()); + case "friendlyFireAlly" -> new WorldsConfig.WorldSettings(current.claiming(), current.powerLoss(), current.friendlyFireFaction(), val, current.maxClaims()); default -> current; }; overrides.put(worldKey, updated); } + private void handleWorldMaxClaimsIncrement(String key, boolean increment) { + String remainder = key.substring("worlds.override.".length()); + int dot = remainder.lastIndexOf('.'); + if (dot <= 0) return; + String worldKey = remainder.substring(0, dot); + + LinkedHashMap overrides = ensurePendingWorldOverrides(); + WorldsConfig.WorldSettings current = overrides.getOrDefault(worldKey, WorldsConfig.WorldSettings.DEFAULTS); + int val = current.maxClaims() != null ? current.maxClaims() : 0; + val = increment ? val + 1 : val - 1; + if (val < 0) val = 0; + + WorldsConfig.WorldSettings updated = new WorldsConfig.WorldSettings( + current.claiming(), current.powerLoss(), current.friendlyFireFaction(), + current.friendlyFireAlly(), val == 0 ? null : val); + overrides.put(worldKey, updated); + } + + private void handleWorldMaxClaimsInput(String key, String input) { + String remainder = key.substring("worlds.override.".length()); + int dot = remainder.lastIndexOf('.'); + if (dot <= 0) return; + String worldKey = remainder.substring(0, dot); + + LinkedHashMap overrides = ensurePendingWorldOverrides(); + WorldsConfig.WorldSettings current = overrides.getOrDefault(worldKey, WorldsConfig.WorldSettings.DEFAULTS); + + Integer val = null; + if (input != null && !input.isBlank()) { + try { + int parsed = Integer.parseInt(input.trim()); + if (parsed > 0) val = parsed; + } catch (NumberFormatException ignored) {} + } + + WorldsConfig.WorldSettings updated = new WorldsConfig.WorldSettings( + current.claiming(), current.powerLoss(), current.friendlyFireFaction(), + current.friendlyFireAlly(), val); + overrides.put(worldKey, updated); + } + /** * Debounced status update for text input fields (numeric, string, color). * Updates only the label color + status bar after the user stops typing. diff --git a/src/main/java/com/hyperfactions/gui/faction/page/ChunkMapPage.java b/src/main/java/com/hyperfactions/gui/faction/page/ChunkMapPage.java index b42923ad..c2c66585 100644 --- a/src/main/java/com/hyperfactions/gui/faction/page/ChunkMapPage.java +++ b/src/main/java/com/hyperfactions/gui/faction/page/ChunkMapPage.java @@ -579,6 +579,10 @@ private void handleClaim(Player player, PlayerRef playerRef, String worldName, case ALREADY_CLAIMED_OTHER -> CommandUtil.prefix().insert(Message.raw(HFMessages.get(playerRef, GuiKeys.MapGui.CLAIM_ALREADY_CLAIMED)).color("#FF5555")); case NOT_ADJACENT -> CommandUtil.prefix().insert(Message.raw(HFMessages.get(playerRef, GuiKeys.MapGui.CLAIM_NOT_ADJACENT)).color("#FF5555")); case MAX_CLAIMS_REACHED -> CommandUtil.prefix().insert(Message.raw(HFMessages.get(playerRef, GuiKeys.MapGui.CLAIM_MAX)).color("#FF5555")); + case WORLD_MAX_CLAIMS_REACHED -> { + Integer wmc = ConfigManager.get().getWorldMaxClaims(worldName); + yield CommandUtil.prefix().insert(Message.raw(HFMessages.get(playerRef, GuiKeys.MapGui.CLAIM_WORLD_MAX, wmc != null ? wmc : "?")).color("#FF5555")); + } case WORLD_NOT_ALLOWED -> CommandUtil.prefix().insert(Message.raw(HFMessages.get(playerRef, GuiKeys.MapGui.CLAIM_WORLD_NOT_ALLOWED)).color("#FF5555")); case ORBISGUARD_PROTECTED -> CommandUtil.prefix().insert(Message.raw(HFMessages.get(playerRef, GuiKeys.MapGui.CLAIM_ORBISGUARD)).color("#FF5555")); default -> CommandUtil.prefix().insert(Message.raw(HFMessages.get(playerRef, GuiKeys.MapGui.CLAIM_FAILED)).color("#FF5555")); @@ -624,6 +628,10 @@ private void handleOverclaim(Player player, PlayerRef playerRef, String worldNam case ALREADY_CLAIMED_ALLY -> CommandUtil.prefix().insert(Message.raw(HFMessages.get(playerRef, GuiKeys.MapGui.OVERCLAIM_ALLY)).color("#FF5555")); case TARGET_HAS_POWER -> CommandUtil.prefix().insert(Message.raw(HFMessages.get(playerRef, GuiKeys.MapGui.OVERCLAIM_HAS_POWER)).color("#FF5555")); case MAX_CLAIMS_REACHED -> CommandUtil.prefix().insert(Message.raw(HFMessages.get(playerRef, GuiKeys.MapGui.OVERCLAIM_MAX)).color("#FF5555")); + case WORLD_MAX_CLAIMS_REACHED -> { + Integer wmc = ConfigManager.get().getWorldMaxClaims(worldName); + yield CommandUtil.prefix().insert(Message.raw(HFMessages.get(playerRef, GuiKeys.MapGui.OVERCLAIM_WORLD_MAX, wmc != null ? wmc : "?")).color("#FF5555")); + } default -> CommandUtil.prefix().insert(Message.raw(HFMessages.get(playerRef, GuiKeys.MapGui.OVERCLAIM_FAILED)).color("#FF5555")); }; diff --git a/src/main/java/com/hyperfactions/gui/faction/page/FactionDashboardPage.java b/src/main/java/com/hyperfactions/gui/faction/page/FactionDashboardPage.java index c8807e0a..f3527c59 100644 --- a/src/main/java/com/hyperfactions/gui/faction/page/FactionDashboardPage.java +++ b/src/main/java/com/hyperfactions/gui/faction/page/FactionDashboardPage.java @@ -724,6 +724,10 @@ private void handleClaimAction(Player player, Ref ref, Store player.sendMessage(MessageUtil.info(playerRef, CommandKeys.Claim.ALREADY_YOURS, MessageUtil.COLOR_GOLD)); case ALREADY_CLAIMED_OTHER, ALREADY_CLAIMED_ALLY, ALREADY_CLAIMED_ENEMY -> player.sendMessage(MessageUtil.error(playerRef, CommandKeys.Claim.ALREADY_CLAIMED)); case MAX_CLAIMS_REACHED -> player.sendMessage(MessageUtil.error(playerRef, CommandKeys.Claim.MAX_CLAIMS)); + case WORLD_MAX_CLAIMS_REACHED -> { + Integer wmc = ConfigManager.get().getWorldMaxClaims(world.getName()); + player.sendMessage(MessageUtil.error(playerRef, CommandKeys.Claim.WORLD_MAX_CLAIMS, wmc != null ? wmc : "?")); + } case WORLD_NOT_ALLOWED -> player.sendMessage(MessageUtil.error(playerRef, CommandKeys.Claim.WORLD_NOT_ALLOWED)); case NOT_ADJACENT -> player.sendMessage(MessageUtil.error(playerRef, CommandKeys.Claim.NOT_CONNECTED)); case INSUFFICIENT_POWER -> player.sendMessage(MessageUtil.error(playerRef, CommandKeys.Claim.INSUFFICIENT_POWER)); diff --git a/src/main/java/com/hyperfactions/manager/ClaimManager.java b/src/main/java/com/hyperfactions/manager/ClaimManager.java index abadf061..8bf068c4 100644 --- a/src/main/java/com/hyperfactions/manager/ClaimManager.java +++ b/src/main/java/com/hyperfactions/manager/ClaimManager.java @@ -255,6 +255,7 @@ public enum ClaimResult { ALREADY_CLAIMED_ENEMY, NOT_ADJACENT, MAX_CLAIMS_REACHED, + WORLD_MAX_CLAIMS_REACHED, INSUFFICIENT_POWER, WORLD_NOT_ALLOWED, CHUNK_NOT_CLAIMED, @@ -406,6 +407,13 @@ public ClaimResult claim(@NotNull UUID playerUuid, @NotNull String world, int ch return ClaimResult.MAX_CLAIMS_REACHED; } + // Check per-world max claims + Integer worldMaxClaims = ConfigManager.get().getWorldMaxClaims(world); + if (worldMaxClaims != null && worldMaxClaims > 0 + && countFactionClaimsInWorld(faction.id(), world) >= worldMaxClaims) { + return ClaimResult.WORLD_MAX_CLAIMS_REACHED; + } + // Check adjacency if required ConfigManager config = ConfigManager.get(); if (config.isOnlyAdjacent() && faction.getClaimCount() > 0) { @@ -591,6 +599,13 @@ public ClaimResult overclaim(@NotNull UUID playerUuid, @NotNull String world, in return ClaimResult.MAX_CLAIMS_REACHED; } + // Check per-world max claims for attacker + Integer worldMaxClaims = ConfigManager.get().getWorldMaxClaims(world); + if (worldMaxClaims != null && worldMaxClaims > 0 + && countFactionClaimsInWorld(attackerFaction.id(), world) >= worldMaxClaims) { + return ClaimResult.WORLD_MAX_CLAIMS_REACHED; + } + // Remove from defender Faction updatedDefender = defenderFaction.withoutClaimAt(world, chunkX, chunkZ) .withLog(FactionLog.create(FactionLog.LogType.OVERCLAIM, @@ -745,6 +760,19 @@ public Set getFactionClaims(@NotNull UUID factionId) { return Collections.unmodifiableSet(claims); } + /** + * Counts the number of claims a faction has in a specific world. + * + * @param factionId the faction ID + * @param world the world name + * @return the number of claims in that world + */ + public int countFactionClaimsInWorld(@NotNull UUID factionId, @NotNull String world) { + Set claims = factionClaimsIndex.get(factionId); + if (claims == null) return 0; + return (int) claims.stream().filter(ck -> ck.world().equals(world)).count(); + } + /** * Checks if removing a chunk would disconnect a faction's claims into islands. * Uses BFS to verify all remaining claims are still connected. diff --git a/src/main/java/com/hyperfactions/platform/PlayerConnectionHandler.java b/src/main/java/com/hyperfactions/platform/PlayerConnectionHandler.java index 0a156445..157f1e99 100644 --- a/src/main/java/com/hyperfactions/platform/PlayerConnectionHandler.java +++ b/src/main/java/com/hyperfactions/platform/PlayerConnectionHandler.java @@ -3,9 +3,11 @@ import com.hyperfactions.HyperFactions; import com.hyperfactions.Permissions; import com.hyperfactions.integration.PermissionManager; +import com.hyperfactions.util.CommandKeys; import com.hyperfactions.util.ErrorHandler; import com.hyperfactions.util.HFMessages; import com.hyperfactions.util.Logger; +import com.hyperfactions.util.MessageUtil; import com.hypixel.hytale.server.core.event.events.player.PlayerChatEvent; import com.hypixel.hytale.server.core.event.events.player.PlayerConnectEvent; import com.hypixel.hytale.server.core.event.events.player.PlayerDisconnectEvent; @@ -115,6 +117,38 @@ public void onPlayerConnect(PlayerConnectEvent event) { } catch (Exception e) { Logger.debugTerritory("Failed to initialize territory tracking for %s: %s", username, e.getMessage()); } + + // Warn officers/leaders if their faction exceeds any per-world claim limit + if (playerFaction != null) { + com.hyperfactions.data.FactionMember member = playerFaction.members().get(uuid); + if (member != null && member.isOfficerOrHigher()) { + checkWorldClaimLimits(playerRef, playerFaction); + } + } + } + + /** + * Checks if a faction exceeds per-world claim limits and warns the player. + */ + private void checkWorldClaimLimits(PlayerRef playerRef, com.hyperfactions.data.Faction faction) { + var configManager = com.hyperfactions.config.ConfigManager.get(); + if (configManager == null) return; + + var worldsConfig = configManager.getWorldsConfig(); + if (worldsConfig == null || !worldsConfig.isEnabled()) return; + + var claimManager = hyperFactions.getClaimManager(); + for (var entry : worldsConfig.getWorlds().entrySet()) { + String worldName = entry.getKey(); + Integer maxClaims = entry.getValue().maxClaims(); + if (maxClaims == null || maxClaims <= 0) continue; + + int currentClaims = claimManager.countFactionClaimsInWorld(faction.id(), worldName); + if (currentClaims > maxClaims) { + playerRef.sendMessage(MessageUtil.info(playerRef, + CommandKeys.Claim.WORLD_OVERCLAIMED, MessageUtil.COLOR_GOLD, currentClaims, worldName, maxClaims)); + } + } } /** diff --git a/src/main/java/com/hyperfactions/util/CommandKeys.java b/src/main/java/com/hyperfactions/util/CommandKeys.java index 40efbe81..7e3a3c28 100644 --- a/src/main/java/com/hyperfactions/util/CommandKeys.java +++ b/src/main/java/com/hyperfactions/util/CommandKeys.java @@ -198,10 +198,12 @@ public static final class Claim { public static final String NOT_OFFICER = "hyperfactions.cmd.claim.not_officer"; public static final String NOT_CONNECTED = "hyperfactions.cmd.claim.not_adjacent"; public static final String MAX_CLAIMS = "hyperfactions.cmd.claim.max_claims"; + public static final String WORLD_MAX_CLAIMS = "hyperfactions.cmd.claim.world_max_claims"; public static final String WORLD_NOT_ALLOWED = "hyperfactions.cmd.claim.world_not_allowed"; public static final String ORBISGUARD = "hyperfactions.cmd.claim.orbisguard"; public static final String ZONE_PROTECTED = "hyperfactions.cmd.claim.zone_protected"; public static final String FAILED = "hyperfactions.cmd.claim.failed"; + public static final String WORLD_OVERCLAIMED = "hyperfactions.cmd.claim.world_overclaimed"; // Unclaim public static final String UNCLAIM_NO_PERMISSION = "hyperfactions.cmd.unclaim.no_permission"; public static final String UNCLAIMED = "hyperfactions.cmd.unclaim.success"; diff --git a/src/main/java/com/hyperfactions/util/GuiKeys.java b/src/main/java/com/hyperfactions/util/GuiKeys.java index f02f4d00..953e0197 100644 --- a/src/main/java/com/hyperfactions/util/GuiKeys.java +++ b/src/main/java/com/hyperfactions/util/GuiKeys.java @@ -950,6 +950,7 @@ public static final class MapGui { public static final String CLAIM_ALREADY_CLAIMED = "hyperfactions_gui.map.claim_already_claimed"; public static final String CLAIM_NOT_ADJACENT = "hyperfactions_gui.map.claim_not_adjacent"; public static final String CLAIM_MAX = "hyperfactions_gui.map.claim_max"; + public static final String CLAIM_WORLD_MAX = "hyperfactions_gui.map.claim_world_max"; public static final String CLAIM_WORLD_NOT_ALLOWED = "hyperfactions_gui.map.claim_world_not_allowed"; public static final String CLAIM_ORBISGUARD = "hyperfactions_gui.map.claim_orbisguard"; public static final String CLAIM_FAILED = "hyperfactions_gui.map.claim_failed"; @@ -969,6 +970,7 @@ public static final class MapGui { public static final String OVERCLAIM_ALLY = "hyperfactions_gui.map.overclaim_ally"; public static final String OVERCLAIM_HAS_POWER = "hyperfactions_gui.map.overclaim_has_power"; public static final String OVERCLAIM_MAX = "hyperfactions_gui.map.overclaim_max"; + public static final String OVERCLAIM_WORLD_MAX = "hyperfactions_gui.map.overclaim_world_max"; public static final String OVERCLAIM_FAILED = "hyperfactions_gui.map.overclaim_failed"; private MapGui() {} diff --git a/src/main/resources/Server/Languages/de-DE/hyperfactions.lang b/src/main/resources/Server/Languages/de-DE/hyperfactions.lang index 12bdcae1..a32194c2 100644 --- a/src/main/resources/Server/Languages/de-DE/hyperfactions.lang +++ b/src/main/resources/Server/Languages/de-DE/hyperfactions.lang @@ -107,12 +107,14 @@ cmd.claim.success = Chunk bei {0}, {1} beansprucht! cmd.claim.not_officer = Sie müssen ein Offizier sein, um Land zu beanspruchen. cmd.claim.already_claimed = Dieser Chunk ist bereits beansprucht. cmd.claim.max_claims = Ihre Fraktion hat die maximale Anzahl an Gebietsansprüchen erreicht. Erhalten Sie mehr Macht! +cmd.claim.world_max_claims = Ihre Fraktion hat die maximale Anzahl an Gebietsansprüchen ({0}) in dieser Welt erreicht. cmd.claim.not_adjacent = Sie müssen angrenzend an bestehendes Territorium beanspruchen. cmd.claim.world_not_allowed = Beanspruchung ist in dieser Welt nicht erlaubt. cmd.claim.orbisguard = Dieses Gebiet ist durch OrbisGuard geschützt. cmd.claim.zone_protected = Dieser Chunk befindet sich in einer SafeZone oder WarZone. cmd.claim.insufficient_power = Ihre Fraktion hat nicht genug Macht, um mehr Land zu beanspruchen. cmd.claim.failed = Chunk konnte nicht beansprucht werden. +cmd.claim.world_overclaimed = Ihre Fraktion hat {0} Gebietsansprüche in {1} (Limit: {2}). Erwägen Sie, überschüssiges Gebiet freizugeben. # ========== Befehle - Einladen ========== cmd.invite.no_permission = Sie haben keine Berechtigung, Spieler einzuladen. diff --git a/src/main/resources/Server/Languages/de-DE/hyperfactions_gui.lang b/src/main/resources/Server/Languages/de-DE/hyperfactions_gui.lang index 5d4e722d..f5486040 100644 --- a/src/main/resources/Server/Languages/de-DE/hyperfactions_gui.lang +++ b/src/main/resources/Server/Languages/de-DE/hyperfactions_gui.lang @@ -738,6 +738,8 @@ map.overclaim_already_yours = Sie besitzen diesen Chunk bereits. map.overclaim_ally = Sie können verbündetes Territorium nicht überbeanspruchen. map.overclaim_has_power = Diese Fraktion hat genug Macht, um ihr Territorium zu verteidigen. map.overclaim_max = Sie haben Ihr maximales Gebietslimit erreicht. +map.claim_world_max = Welt-Gebietslimit erreicht ({0}). +map.overclaim_world_max = Welt-Gebietslimit erreicht ({0}). map.overclaim_failed = Überbeanspruchung des Chunks fehlgeschlagen. # ========== Fraktion erstellen ========== create.title = Erstellen Sie Ihre Fraktion diff --git a/src/main/resources/Server/Languages/en-US/hyperfactions.lang b/src/main/resources/Server/Languages/en-US/hyperfactions.lang index 4e80eed3..11148343 100644 --- a/src/main/resources/Server/Languages/en-US/hyperfactions.lang +++ b/src/main/resources/Server/Languages/en-US/hyperfactions.lang @@ -107,12 +107,14 @@ cmd.claim.success = Claimed chunk at {0}, {1}! cmd.claim.not_officer = You must be an officer to claim land. cmd.claim.already_claimed = This chunk is already claimed. cmd.claim.max_claims = Your faction has reached max claims. Get more power! +cmd.claim.world_max_claims = Your faction has reached the maximum claims ({0}) allowed in this world. cmd.claim.not_adjacent = You must claim adjacent to existing territory. cmd.claim.world_not_allowed = Claiming is not allowed in this world. cmd.claim.orbisguard = This area is protected by OrbisGuard. cmd.claim.zone_protected = This chunk is in a safezone or warzone. cmd.claim.insufficient_power = Your faction doesn't have enough power to claim more land. cmd.claim.failed = Failed to claim chunk. +cmd.claim.world_overclaimed = Your faction has {0} claims in {1} (limit: {2}). Consider unclaiming excess territory. # ========== Commands - Invite ========== cmd.invite.no_permission = You don't have permission to invite players. diff --git a/src/main/resources/Server/Languages/en-US/hyperfactions_gui.lang b/src/main/resources/Server/Languages/en-US/hyperfactions_gui.lang index 9f68570a..2da2fe2d 100644 --- a/src/main/resources/Server/Languages/en-US/hyperfactions_gui.lang +++ b/src/main/resources/Server/Languages/en-US/hyperfactions_gui.lang @@ -738,6 +738,8 @@ map.overclaim_already_yours = You already own this chunk. map.overclaim_ally = You cannot overclaim allied territory. map.overclaim_has_power = This faction has enough power to defend their territory. map.overclaim_max = You have reached your maximum claim limit. +map.claim_world_max = Reached world claim limit ({0}). +map.overclaim_world_max = Reached world claim limit ({0}). map.overclaim_failed = Failed to overclaim chunk. # ========== Create Faction Page ========== create.title = Create Your Faction diff --git a/src/main/resources/Server/Languages/es-ES/hyperfactions.lang b/src/main/resources/Server/Languages/es-ES/hyperfactions.lang index 99783a8f..5e76a0ac 100644 --- a/src/main/resources/Server/Languages/es-ES/hyperfactions.lang +++ b/src/main/resources/Server/Languages/es-ES/hyperfactions.lang @@ -107,12 +107,14 @@ cmd.claim.success = Chunk reclamado en {0}, {1}! cmd.claim.not_officer = Debes ser oficial para reclamar territorio. cmd.claim.already_claimed = Este chunk ya esta reclamado. cmd.claim.max_claims = Tu faccion alcanzo el maximo de reclamos. Consigue mas poder! +cmd.claim.world_max_claims = Tu faccion ha alcanzado el maximo de reclamos ({0}) permitidos en este mundo. cmd.claim.not_adjacent = Debes reclamar junto a territorio existente. cmd.claim.world_not_allowed = No se permite reclamar en este mundo. cmd.claim.orbisguard = Esta area esta protegida por OrbisGuard. cmd.claim.zone_protected = Este chunk esta en una zona segura o de guerra. cmd.claim.insufficient_power = Tu faccion no tiene suficiente poder para reclamar mas territorio. cmd.claim.failed = No se pudo reclamar el chunk. +cmd.claim.world_overclaimed = Tu faccion tiene {0} reclamos en {1} (limite: {2}). Considera liberar territorio excedente. # ========== Comandos - Invitar ========== cmd.invite.no_permission = No tienes permiso para invitar jugadores. diff --git a/src/main/resources/Server/Languages/es-ES/hyperfactions_gui.lang b/src/main/resources/Server/Languages/es-ES/hyperfactions_gui.lang index 6a730430..ef3acf78 100644 --- a/src/main/resources/Server/Languages/es-ES/hyperfactions_gui.lang +++ b/src/main/resources/Server/Languages/es-ES/hyperfactions_gui.lang @@ -738,6 +738,8 @@ map.overclaim_already_yours = Ya posees este chunk. map.overclaim_ally = No puedes sobrereclamar territorio aliado. map.overclaim_has_power = Esta faccion tiene suficiente poder para defender su territorio. map.overclaim_max = Has alcanzado tu limite maximo de reclamos. +map.claim_world_max = Limite de reclamos del mundo alcanzado ({0}). +map.overclaim_world_max = Limite de reclamos del mundo alcanzado ({0}). map.overclaim_failed = No se pudo sobrereclamar el chunk. # ========== Pagina de Crear Faccion ========== create.title = Crea Tu Faccion diff --git a/src/main/resources/Server/Languages/fr-FR/hyperfactions.lang b/src/main/resources/Server/Languages/fr-FR/hyperfactions.lang index 6d3a878c..fd32dbb4 100644 --- a/src/main/resources/Server/Languages/fr-FR/hyperfactions.lang +++ b/src/main/resources/Server/Languages/fr-FR/hyperfactions.lang @@ -107,12 +107,14 @@ cmd.claim.success = Chunk revendiqué en {0}, {1} ! cmd.claim.not_officer = Vous devez être officier pour revendiquer des terres. cmd.claim.already_claimed = Ce chunk est déjà revendiqué. cmd.claim.max_claims = Votre faction a atteint le maximum de revendications. Gagnez plus de puissance ! +cmd.claim.world_max_claims = Votre faction a atteint le maximum de revendications ({0}) autorisées dans ce monde. cmd.claim.not_adjacent = Vous devez revendiquer un chunk adjacent à votre territoire existant. cmd.claim.world_not_allowed = La revendication n'est pas autorisée dans ce monde. cmd.claim.orbisguard = Cette zone est protégée par OrbisGuard. cmd.claim.zone_protected = Ce chunk se trouve dans une SafeZone ou une WarZone. cmd.claim.insufficient_power = Votre faction n'a pas assez de puissance pour revendiquer plus de territoire. cmd.claim.failed = Échec de la revendication du chunk. +cmd.claim.world_overclaimed = Votre faction possède {0} revendications dans {1} (limite : {2}). Envisagez de libérer le territoire excédentaire. # ========== Commandes - Inviter ========== cmd.invite.no_permission = Vous n'avez pas la permission d'inviter des joueurs. diff --git a/src/main/resources/Server/Languages/fr-FR/hyperfactions_gui.lang b/src/main/resources/Server/Languages/fr-FR/hyperfactions_gui.lang index fa65adf6..4309d71f 100644 --- a/src/main/resources/Server/Languages/fr-FR/hyperfactions_gui.lang +++ b/src/main/resources/Server/Languages/fr-FR/hyperfactions_gui.lang @@ -738,6 +738,8 @@ map.overclaim_already_yours = Vous possédez déjà ce chunk. map.overclaim_ally = Vous ne pouvez pas surrevendiquer le territoire d'un allié. map.overclaim_has_power = Cette faction a assez de puissance pour défendre son territoire. map.overclaim_max = Vous avez atteint votre limite maximale de revendications. +map.claim_world_max = Limite de revendications du monde atteinte ({0}). +map.overclaim_world_max = Limite de revendications du monde atteinte ({0}). map.overclaim_failed = Échec de la surrevendication du chunk. # ========== Page de Création de Faction ========== create.title = Créer Votre Faction diff --git a/src/main/resources/Server/Languages/it-IT/hyperfactions.lang b/src/main/resources/Server/Languages/it-IT/hyperfactions.lang index 9b96e849..c82a484f 100644 --- a/src/main/resources/Server/Languages/it-IT/hyperfactions.lang +++ b/src/main/resources/Server/Languages/it-IT/hyperfactions.lang @@ -107,12 +107,14 @@ cmd.claim.success = Chunk rivendicato a {0}, {1}! cmd.claim.not_officer = Devi essere un ufficiale per rivendicare territori. cmd.claim.already_claimed = Questo chunk è già rivendicato. cmd.claim.max_claims = La tua fazione ha raggiunto il massimo di territori. Ottieni più potere! +cmd.claim.world_max_claims = La tua fazione ha raggiunto il massimo di territori ({0}) consentiti in questo mondo. cmd.claim.not_adjacent = Devi rivendicare un chunk adiacente al territorio esistente. cmd.claim.world_not_allowed = La rivendicazione non è permessa in questo mondo. cmd.claim.orbisguard = Quest'area è protetta da OrbisGuard. cmd.claim.zone_protected = Questo chunk si trova in una SafeZone o WarZone. cmd.claim.insufficient_power = La tua fazione non ha abbastanza potere per rivendicare altro territorio. cmd.claim.failed = Impossibile rivendicare il chunk. +cmd.claim.world_overclaimed = La tua fazione ha {0} rivendicazioni in {1} (limite: {2}). Considera di liberare il territorio in eccesso. # ========== Comandi - Invito ========== cmd.invite.no_permission = Non hai il permesso di invitare giocatori. diff --git a/src/main/resources/Server/Languages/it-IT/hyperfactions_gui.lang b/src/main/resources/Server/Languages/it-IT/hyperfactions_gui.lang index acc94d72..1e6e0802 100644 --- a/src/main/resources/Server/Languages/it-IT/hyperfactions_gui.lang +++ b/src/main/resources/Server/Languages/it-IT/hyperfactions_gui.lang @@ -738,6 +738,8 @@ map.overclaim_already_yours = Possiedi già questo chunk. map.overclaim_ally = Non puoi conquistare territorio alleato. map.overclaim_has_power = Questa fazione ha abbastanza potere per difendere il proprio territorio. map.overclaim_max = Hai raggiunto il limite massimo di territori. +map.claim_world_max = Raggiunto il limite di territori del mondo ({0}). +map.overclaim_world_max = Raggiunto il limite di territori del mondo ({0}). map.overclaim_failed = Impossibile conquistare il chunk. # ========== Pagina Creazione Fazione ========== create.title = Crea la Tua Fazione diff --git a/src/main/resources/Server/Languages/nl-NL/hyperfactions.lang b/src/main/resources/Server/Languages/nl-NL/hyperfactions.lang index 7f7bd098..7ef0d6c3 100644 --- a/src/main/resources/Server/Languages/nl-NL/hyperfactions.lang +++ b/src/main/resources/Server/Languages/nl-NL/hyperfactions.lang @@ -107,12 +107,14 @@ cmd.claim.success = Gebied geclaimd op {0}, {1}! cmd.claim.not_officer = Je moet een officier zijn om land te claimen. cmd.claim.already_claimed = Dit gebied is al geclaimd. cmd.claim.max_claims = Je factie heeft het maximum aantal gebieden bereikt. Krijg meer kracht! +cmd.claim.world_max_claims = Je factie heeft het maximum aantal gebieden ({0}) bereikt dat in deze wereld is toegestaan. cmd.claim.not_adjacent = Je moet aangrenzend aan bestaand territorium claimen. cmd.claim.world_not_allowed = Claimen is niet toegestaan in deze wereld. cmd.claim.orbisguard = Dit gebied wordt beschermd door OrbisGuard. cmd.claim.zone_protected = Dit gebied bevindt zich in een SafeZone of WarZone. cmd.claim.insufficient_power = Je factie heeft niet genoeg kracht om meer land te claimen. cmd.claim.failed = Gebied claimen mislukt. +cmd.claim.world_overclaimed = Je factie heeft {0} claims in {1} (limiet: {2}). Overweeg om overtollig gebied vrij te geven. # ========== Commando's - Uitnodigen ========== cmd.invite.no_permission = Je hebt geen toestemming om spelers uit te nodigen. diff --git a/src/main/resources/Server/Languages/nl-NL/hyperfactions_gui.lang b/src/main/resources/Server/Languages/nl-NL/hyperfactions_gui.lang index 824e7dad..c40ef0ad 100644 --- a/src/main/resources/Server/Languages/nl-NL/hyperfactions_gui.lang +++ b/src/main/resources/Server/Languages/nl-NL/hyperfactions_gui.lang @@ -738,6 +738,8 @@ map.overclaim_already_yours = Je bezit dit gebied al. map.overclaim_ally = Je kunt bondgenootterritorium niet overnemen. map.overclaim_has_power = Deze factie heeft genoeg kracht om hun territorium te verdedigen. map.overclaim_max = Je hebt het maximale aantal claims bereikt. +map.claim_world_max = Wereldclaimlimiet bereikt ({0}). +map.overclaim_world_max = Wereldclaimlimiet bereikt ({0}). map.overclaim_failed = Overnemen mislukt. # ========== Factie Aanmaken Pagina ========== create.title = Maak Jouw Factie diff --git a/src/main/resources/Server/Languages/pl-PL/hyperfactions.lang b/src/main/resources/Server/Languages/pl-PL/hyperfactions.lang index dc451f2f..26f24536 100644 --- a/src/main/resources/Server/Languages/pl-PL/hyperfactions.lang +++ b/src/main/resources/Server/Languages/pl-PL/hyperfactions.lang @@ -107,12 +107,14 @@ cmd.claim.success = Zajęto chunk na {0}, {1}! cmd.claim.not_officer = Musisz być oficerem, aby zajmować teren. cmd.claim.already_claimed = Ten chunk jest już zajęty. cmd.claim.max_claims = Twoja frakcja osiągnęła maksymalną liczbę terenów. Zdobądź więcej mocy! +cmd.claim.world_max_claims = Twoja frakcja osiągnęła maksymalną liczbę terenów ({0}) dozwolonych w tym świecie. cmd.claim.not_adjacent = Musisz zajmować teren przylegający do istniejącego terytorium. cmd.claim.world_not_allowed = Zajmowanie terenu jest niedozwolone w tym świecie. cmd.claim.orbisguard = Ten obszar jest chroniony przez OrbisGuard. cmd.claim.zone_protected = Ten chunk znajduje się w strefie bezpiecznej lub wojennej. cmd.claim.insufficient_power = Twoja frakcja nie ma wystarczająco mocy, aby zająć więcej terenu. cmd.claim.failed = Nie udało się zająć chunka. +cmd.claim.world_overclaimed = Twoja frakcja ma {0} zajętych chunków w {1} (limit: {2}). Rozważ zwolnienie nadmiarowego terytorium. # ========== Komendy - Zaproszenia ========== cmd.invite.no_permission = Nie masz uprawnień do zapraszania graczy. diff --git a/src/main/resources/Server/Languages/pl-PL/hyperfactions_gui.lang b/src/main/resources/Server/Languages/pl-PL/hyperfactions_gui.lang index 14e74dcc..b0759569 100644 --- a/src/main/resources/Server/Languages/pl-PL/hyperfactions_gui.lang +++ b/src/main/resources/Server/Languages/pl-PL/hyperfactions_gui.lang @@ -738,6 +738,8 @@ map.overclaim_already_yours = Już posiadasz ten chunk. map.overclaim_ally = Nie możesz przejąć terytorium sojusznika. map.overclaim_has_power = Ta frakcja ma wystarczająco mocy, aby obronić swoje terytorium. map.overclaim_max = Osiągnąłeś maksymalny limit terenów. +map.claim_world_max = Osiągnięto limit terenów świata ({0}). +map.overclaim_world_max = Osiągnięto limit terenów świata ({0}). map.overclaim_failed = Nie udało się przejąć chunka. # ========== Strona tworzenia frakcji ========== create.title = Utwórz swoją frakcję diff --git a/src/main/resources/Server/Languages/pt-BR/hyperfactions.lang b/src/main/resources/Server/Languages/pt-BR/hyperfactions.lang index e3f3eec7..e426a0a6 100644 --- a/src/main/resources/Server/Languages/pt-BR/hyperfactions.lang +++ b/src/main/resources/Server/Languages/pt-BR/hyperfactions.lang @@ -107,12 +107,14 @@ cmd.claim.success = Chunk reivindicado em {0}, {1}! cmd.claim.not_officer = Você precisa ser oficial para reivindicar território. cmd.claim.already_claimed = Este chunk já está reivindicado. cmd.claim.max_claims = Sua facção atingiu o máximo de reivindicações. Consiga mais poder! +cmd.claim.world_max_claims = Sua facção atingiu o máximo de reivindicações ({0}) permitidas neste mundo. cmd.claim.not_adjacent = Você deve reivindicar adjacente ao território existente. cmd.claim.world_not_allowed = Reivindicações não são permitidas neste mundo. cmd.claim.orbisguard = Esta área é protegida pelo OrbisGuard. cmd.claim.zone_protected = Este chunk está em uma SafeZone ou WarZone. cmd.claim.insufficient_power = Sua facção não tem poder suficiente para reivindicar mais território. cmd.claim.failed = Falha ao reivindicar chunk. +cmd.claim.world_overclaimed = Sua facção tem {0} reivindicações em {1} (limite: {2}). Considere liberar território excedente. # ========== Comandos - Convidar ========== cmd.invite.no_permission = Você não tem permissão para convidar jogadores. diff --git a/src/main/resources/Server/Languages/pt-BR/hyperfactions_gui.lang b/src/main/resources/Server/Languages/pt-BR/hyperfactions_gui.lang index 310ab4dd..a107fa19 100644 --- a/src/main/resources/Server/Languages/pt-BR/hyperfactions_gui.lang +++ b/src/main/resources/Server/Languages/pt-BR/hyperfactions_gui.lang @@ -738,6 +738,8 @@ map.overclaim_already_yours = Você já possui este chunk. map.overclaim_ally = Você não pode conquistar território aliado. map.overclaim_has_power = Esta facção tem poder suficiente para defender seu território. map.overclaim_max = Você atingiu o limite máximo de reivindicações. +map.claim_world_max = Limite de reivindicações do mundo atingido ({0}). +map.overclaim_world_max = Limite de reivindicações do mundo atingido ({0}). map.overclaim_failed = Falha ao conquistar chunk. # ========== Página de Criação de Facção ========== create.title = Crie Sua Facção diff --git a/src/main/resources/Server/Languages/ru-RU/hyperfactions.lang b/src/main/resources/Server/Languages/ru-RU/hyperfactions.lang index 54d02db5..5d78958f 100644 --- a/src/main/resources/Server/Languages/ru-RU/hyperfactions.lang +++ b/src/main/resources/Server/Languages/ru-RU/hyperfactions.lang @@ -107,12 +107,14 @@ cmd.claim.success = Чанк захвачен в {0}, {1}! cmd.claim.not_officer = Вы должны быть Офицером, чтобы захватывать территорию. cmd.claim.already_claimed = Этот чанк уже захвачен. cmd.claim.max_claims = Ваша фракция достигла предела территорий. Получите больше Силы! +cmd.claim.world_max_claims = Ваша фракция достигла предела территорий ({0}) в этом мире. cmd.claim.not_adjacent = Вы можете захватывать только территории, смежные с вашими. cmd.claim.world_not_allowed = Захват территории в этом мире запрещён. cmd.claim.orbisguard = Эта область защищена OrbisGuard. cmd.claim.zone_protected = Этот чанк находится в SafeZone или WarZone. cmd.claim.insufficient_power = У вашей фракции недостаточно Силы для захвата новых территорий. cmd.claim.failed = Не удалось захватить чанк. +cmd.claim.world_overclaimed = Ваша фракция имеет {0} захваченных чанков в {1} (лимит: {2}). Рассмотрите возможность освобождения лишней территории. # ========== Команды - Приглашение ========== cmd.invite.no_permission = У вас нет прав приглашать игроков. diff --git a/src/main/resources/Server/Languages/ru-RU/hyperfactions_gui.lang b/src/main/resources/Server/Languages/ru-RU/hyperfactions_gui.lang index fbb48362..2017148d 100644 --- a/src/main/resources/Server/Languages/ru-RU/hyperfactions_gui.lang +++ b/src/main/resources/Server/Languages/ru-RU/hyperfactions_gui.lang @@ -738,6 +738,8 @@ map.overclaim_already_yours = Вы уже владеете этим чанком map.overclaim_ally = Вы не можете перезахватить территорию союзника. map.overclaim_has_power = У этой фракции достаточно Силы для защиты своей территории. map.overclaim_max = Вы достигли предела территорий. +map.claim_world_max = Достигнут лимит территорий мира ({0}). +map.overclaim_world_max = Достигнут лимит территорий мира ({0}). map.overclaim_failed = Не удалось выполнить перезахват. # ========== Страница создания фракции ========== create.title = Создайте свою фракцию diff --git a/src/main/resources/Server/Languages/tl-PH/hyperfactions.lang b/src/main/resources/Server/Languages/tl-PH/hyperfactions.lang index bdcb8e33..6d0d2efd 100644 --- a/src/main/resources/Server/Languages/tl-PH/hyperfactions.lang +++ b/src/main/resources/Server/Languages/tl-PH/hyperfactions.lang @@ -107,12 +107,14 @@ cmd.claim.success = Na-claim ang chunk sa {0}, {1}! cmd.claim.not_officer = Dapat ikaw ay isang opisyal upang mag-claim ng lupa. cmd.claim.already_claimed = Ang chunk na ito ay naka-claim na. cmd.claim.max_claims = Naabot na ng iyong paksyon ang maximum na claim. Kumuha ng higit pang kapangyarihan! +cmd.claim.world_max_claims = Naabot na ng iyong paksyon ang maximum na claim ({0}) na pinapayagan sa mundong ito. cmd.claim.not_adjacent = Dapat kang mag-claim na katabi ng umiiral na teritoryo. cmd.claim.world_not_allowed = Hindi pinapayagan ang pag-claim sa mundong ito. cmd.claim.orbisguard = Ang lugar na ito ay protektado ng OrbisGuard. cmd.claim.zone_protected = Ang chunk na ito ay nasa safezone o warzone. cmd.claim.insufficient_power = Kulang ang kapangyarihan ng iyong paksyon upang mag-claim ng higit pang lupa. cmd.claim.failed = Nabigo ang pag-claim ng chunk. +cmd.claim.world_overclaimed = Ang iyong paksyon ay may {0} na mga claim sa {1} (limitasyon: {2}). Isaalang-alang ang pag-unclaim ng sobrang teritoryo. # ========== Mga Utos - Imbitahan ========== cmd.invite.no_permission = Wala kang pahintulot na mag-imbita ng mga manlalaro. diff --git a/src/main/resources/Server/Languages/tl-PH/hyperfactions_gui.lang b/src/main/resources/Server/Languages/tl-PH/hyperfactions_gui.lang index c9b39c6b..d5c8fa46 100644 --- a/src/main/resources/Server/Languages/tl-PH/hyperfactions_gui.lang +++ b/src/main/resources/Server/Languages/tl-PH/hyperfactions_gui.lang @@ -738,6 +738,8 @@ map.overclaim_already_yours = Pagmamay-ari mo na ang chunk na ito. map.overclaim_ally = Hindi mo maaaring i-overclaim ang teritoryo ng kakampi. map.overclaim_has_power = Ang paksyon na ito ay may sapat na kapangyarihan upang ipagtanggol ang kanilang teritoryo. map.overclaim_max = Naabot mo na ang maximum na claim limit. +map.claim_world_max = Naabot ang claim limit ng mundo ({0}). +map.overclaim_world_max = Naabot ang claim limit ng mundo ({0}). map.overclaim_failed = Nabigo ang pag-overclaim ng chunk. # ========== Pahina ng Paggawa ng Paksyon ========== create.title = Gumawa ng Iyong Paksyon