diff --git a/manage_languages.py b/manage_languages.py index ddaf733776b..2882f18d3b4 100644 --- a/manage_languages.py +++ b/manage_languages.py @@ -23,7 +23,7 @@ def ppprint(data): class JsonHelpers: @staticmethod def load(filename: str) -> dict: - with open(filename, 'r') as file: + with open(filename, 'r', encoding='utf-8') as file: return json.load(file) @staticmethod @@ -117,7 +117,7 @@ def find_all_used_keys(self, expected_keys=[]) -> set: for file in files: if file.rpartition('.')[-1] in SOURCE_EXTENSIONS: filename = os.path.join(root, file) - with open(filename, 'r') as f: + with open(filename, 'r', encoding='utf-8') as f: data = f.read() # Loads in entire file at once for k in self.TRANSLATION_KEY.findall(data): used.add(k) diff --git a/src/main/java/emu/grasscutter/command/commands/SetStatsCommand.java b/src/main/java/emu/grasscutter/command/commands/SetStatsCommand.java index 2d3c092bc7a..3e8456fd2e6 100644 --- a/src/main/java/emu/grasscutter/command/commands/SetStatsCommand.java +++ b/src/main/java/emu/grasscutter/command/commands/SetStatsCommand.java @@ -6,14 +6,23 @@ import emu.grasscutter.command.Command; import emu.grasscutter.command.CommandHandler; +import emu.grasscutter.game.avatar.Avatar; import emu.grasscutter.game.entity.EntityAvatar; import emu.grasscutter.game.player.Player; import emu.grasscutter.game.props.FightProperty; import emu.grasscutter.server.packet.send.PacketEntityFightPropUpdateNotify; -@Command(label = "setStats", aliases = {"stats", "stat"}, usage = {" "}, permission = "player.setstats", permissionTargeted = "player.setstats.others") +@Command( + label = "setStats", + aliases = {"stats", "stat"}, + usage = { + "[set] ", + "(lock|freeze) []", // Can lock to current value + "(unlock|unfreeze) "}, + permission = "player.setstats", + permissionTargeted = "player.setstats.others") public final class SetStatsCommand implements CommandHandler { - static class Stat { + private static class Stat { String name; FightProperty prop; @@ -27,9 +36,21 @@ public Stat(String name, FightProperty prop) { this.prop = prop; } } - - Map stats; - + + private static enum Action { + ACTION_SET("commands.generic.set_to", "commands.generic.set_for_to"), + ACTION_LOCK("commands.setStats.locked_to", "commands.setStats.locked_for_to"), + ACTION_UNLOCK("commands.setStats.unlocked", "commands.setStats.unlocked_for"); + public final String messageKeySelf; + public final String messageKeyOther; + private Action(String messageKeySelf, String messageKeyOther) { + this.messageKeySelf = messageKeySelf; + this.messageKeyOther = messageKeyOther; + } + } + + private Map stats; + public SetStatsCommand() { this.stats = new HashMap<>(); for (String key : FightProperty.getShortNames()) { @@ -62,50 +83,97 @@ public SetStatsCommand() { this.stats.put("ephys", this.stats.get("phys%")); } + public static float parsePercent(String input) throws NumberFormatException { + if (input.endsWith("%")) { + return Float.parseFloat(input.substring(0, input.length()-1))/100f; + } else { + return Float.parseFloat(input); + } + } + @Override public void execute(Player sender, Player targetPlayer, List args) { - String statStr; + String statStr = null; String valueStr; + float value = 0f; - if (args.size() == 2) { - statStr = args.get(0).toLowerCase(); - valueStr = args.get(1); - } else { + if (args.size() < 2) { sendUsageMessage(sender); return; } + // Get the action and stat + String arg0 = args.remove(0).toLowerCase(); + Action action = switch (arg0) { + default -> {statStr = arg0; yield Action.ACTION_SET;} // Implicit set command + case "set" -> Action.ACTION_SET; // Explicit set command + case "lock", "freeze" -> Action.ACTION_LOCK; + case "unlock", "unfreeze" -> Action.ACTION_UNLOCK; + }; + if (statStr == null) { + statStr = args.remove(0).toLowerCase(); + } + if (!stats.containsKey(statStr)) { + sendUsageMessage(sender); // Invalid stat or action + return; + } + Stat stat = stats.get(statStr); EntityAvatar entity = targetPlayer.getTeamManager().getCurrentAvatarEntity(); + Avatar avatar = entity.getAvatar(); - float value; + // Get the value if the action requires it try { - if (valueStr.endsWith("%")) { - value = Float.parseFloat(valueStr.substring(0, valueStr.length()-1))/100f; - } else { - value = Float.parseFloat(valueStr); + switch (action) { + case ACTION_LOCK: + if (args.isEmpty()) { // Lock to current value + value = avatar.getFightProperty(stat.prop); + break; + } // Else fall-through and lock to supplied value + case ACTION_SET: + value = parsePercent(args.remove(0)); + break; + case ACTION_UNLOCK: + break; } } catch (NumberFormatException ignored) { CommandHandler.sendTranslatedMessage(sender, "commands.generic.invalid.statValue"); return; + } catch (IndexOutOfBoundsException ignored) { + sendUsageMessage(sender); + return; } - if (stats.containsKey(statStr)) { - Stat stat = stats.get(statStr); - entity.setFightProperty(stat.prop, value); - entity.getWorld().broadcastPacket(new PacketEntityFightPropUpdateNotify(entity, stat.prop)); - if (FightProperty.isPercentage(stat.prop)) { - valueStr = String.format("%.1f%%", value * 100f); - } else { - valueStr = String.format("%.0f", value); - } - if (targetPlayer == sender) { - CommandHandler.sendTranslatedMessage(sender, "commands.generic.set_to", stat.name, valueStr); - } else { - String uidStr = targetPlayer.getAccount().getId(); - CommandHandler.sendTranslatedMessage(sender, "commands.generic.set_for_to", stat.name, uidStr, valueStr); - } - } else { + if (!args.isEmpty()) { // Leftover arguments! sendUsageMessage(sender); + return; + } + + switch (action) { + case ACTION_SET: + entity.setFightProperty(stat.prop, value); + entity.getWorld().broadcastPacket(new PacketEntityFightPropUpdateNotify(entity, stat.prop)); + break; + case ACTION_LOCK: + avatar.getFightPropOverrides().put(stat.prop.getId(), value); + avatar.recalcStats(); + break; + case ACTION_UNLOCK: + avatar.getFightPropOverrides().remove(stat.prop.getId()); + avatar.recalcStats(); + break; + } + + // Report action + if (FightProperty.isPercentage(stat.prop)) { + valueStr = String.format("%.1f%%", value * 100f); + } else { + valueStr = String.format("%.0f", value); + } + if (targetPlayer == sender) { + CommandHandler.sendTranslatedMessage(sender, action.messageKeySelf, stat.name, valueStr); + } else { + String uidStr = targetPlayer.getAccount().getId(); + CommandHandler.sendTranslatedMessage(sender, action.messageKeyOther, stat.name, uidStr, valueStr); } return; } diff --git a/src/main/java/emu/grasscutter/game/avatar/Avatar.java b/src/main/java/emu/grasscutter/game/avatar/Avatar.java index 5a42ce92574..37f696f4810 100644 --- a/src/main/java/emu/grasscutter/game/avatar/Avatar.java +++ b/src/main/java/emu/grasscutter/game/avatar/Avatar.java @@ -63,6 +63,7 @@ import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; +import lombok.Getter; @Entity(value = "avatars", useDiscriminator = false) public class Avatar { @@ -85,6 +86,7 @@ public class Avatar { @Transient private final Int2ObjectMap equips; @Transient private final Int2FloatOpenHashMap fightProp; + @Transient @Getter private final Int2FloatOpenHashMap fightPropOverrides; @Transient private Set extraAbilityEmbryos; private List fetters; @@ -111,6 +113,7 @@ public class Avatar { public Avatar() { this.equips = new Int2ObjectOpenHashMap<>(); this.fightProp = new Int2FloatOpenHashMap(); + this.fightPropOverrides = new Int2FloatOpenHashMap(); this.extraAbilityEmbryos = new HashSet<>(); this.proudSkillBonusMap = new HashMap<>(); this.fetters = new ArrayList<>(); // TODO Move to avatar @@ -728,6 +731,9 @@ public void recalcStats(boolean forceSendAbilityChange) { (getFightProperty(FightProperty.FIGHT_PROP_BASE_DEFENSE) * (1f + getFightProperty(FightProperty.FIGHT_PROP_DEFENSE_PERCENT))) + getFightProperty(FightProperty.FIGHT_PROP_DEFENSE) ); + // Reapply all overrides + this.fightProp.putAll(this.fightPropOverrides); + // Set current hp this.setFightProperty(FightProperty.FIGHT_PROP_CUR_HP, this.getFightProperty(FightProperty.FIGHT_PROP_MAX_HP) * hpPercent); diff --git a/src/main/resources/languages/en-US.json b/src/main/resources/languages/en-US.json index c1b9a6d2446..c6cafc30123 100644 --- a/src/main/resources/languages/en-US.json +++ b/src/main/resources/languages/en-US.json @@ -274,7 +274,11 @@ "description": "Sets accountwide properties. Things like godmode can be enabled this way, as well as changing things like unlocked abyss floor and battle pass progress.\n\tValues for : godmode | nostamina | unlimitedenergy | abyss | worldlevel | bplevel\n\t(cont.) see PlayerProperty enum for other possible values, of form PROP_MAX_SPRING_VOLUME -> max_spring_volume" }, "setStats": { - "description": "Sets fight property for your current active character\n\tValues for : hp | maxhp | def | atk | em | er | crate | cdmg | cdr | heal | heali | shield | defi\n\t(cont.) Elemental DMG Bonus: epyro | ecryo | ehydro | egeo | edendro | eelectro | ephys\n\t(cont.) Elemental RES: respyro | rescryo | reshydro | resgeo | resdendro | reselectro | resphys" + "description": "Sets fight property for your current active character\n\tValues for : hp | maxhp | def | atk | em | er | crate | cdmg | cdr | heal | heali | shield | defi\n\t(cont.) Elemental DMG Bonus: epyro | ecryo | ehydro | egeo | edendro | eelectro | ephys\n\t(cont.) Elemental RES: respyro | rescryo | reshydro | resgeo | resdendro | reselectro | resphys", + "locked_to": "%s locked to %s.", + "locked_for_to": "%s for %s locked to %s.", + "unlocked": "%s unlocked.", + "unlocked_for": "%s for %s unlocked." }, "spawn": { "success": "Spawned %s of %s.", diff --git a/src/main/resources/languages/es-ES.json b/src/main/resources/languages/es-ES.json index 7899f9f65df..9fca37f2fe1 100644 --- a/src/main/resources/languages/es-ES.json +++ b/src/main/resources/languages/es-ES.json @@ -274,7 +274,11 @@ "description": "Establece propiedades de la cuenta. Cosas como el modo Dios pueden ser establecidos con este comando, además de cambiar cosas como desbloquear pisos del abusmo o progreso del pase de batalla.\n\tValores para : godmode | nostamina | unlimitedenergy | abyss | worldlevel | bplevel\n\t(cont.) Observa PlayerProperty enum para ver otros posibles valores, de la forma PROP_MAX_SPRING_VOLUME -> max_spring_volume" }, "setStats": { - "description": "Establece propiedades de combate para tu personaje actual\n\tValores para : hp | maxhp | def | atk | em | er | crate | cdmg | cdr | heal | heali | shield | defi\n\t(cont.) Bonus de daño elemental: epyro | ecryo | ehydro | egeo | edendro | eelectro | ephys\n\t(cont.) Resistencia elemental: respyro | rescryo | reshydro | resgeo | resdendro | reselectro | resphys" + "description": "Establece propiedades de combate para tu personaje actual\n\tValores para : hp | maxhp | def | atk | em | er | crate | cdmg | cdr | heal | heali | shield | defi\n\t(cont.) Bonus de daño elemental: epyro | ecryo | ehydro | egeo | edendro | eelectro | ephys\n\t(cont.) Resistencia elemental: respyro | rescryo | reshydro | resgeo | resdendro | reselectro | resphys", + "locked_to": "🇺🇸%s locked to %s.", + "locked_for_to": "🇺🇸%s for %s locked to %s.", + "unlocked": "🇺🇸%s unlocked.", + "unlocked_for": "🇺🇸%s for %s unlocked." }, "spawn": { "success": "Generados %s de %s.", @@ -334,6 +338,10 @@ "invalid_time": "No se puede establecer la marca de tiempo.", "description": "Beta a un jugador" }, + "unlockall": { + "success": "🇺🇸Unlocked all open states for %s.", + "description": "🇺🇸Unlocks all open states for a player." + }, "unban": { "success": "Exitoso.", "failure": "Error, jugador no encontrado.", @@ -355,24 +363,24 @@ }, "documentation": { "handbook": { - "title": "GM Handbook", + "title": "🇺🇸GM Handbook", "title_commands": "Comandos", "title_avatars": "Avatares", "title_items": "Objetos", "title_scenes": "Escenario", "title_monsters": "Monstruos", - "header_id": "Id", + "header_id": "🇺🇸Id", "header_command": "Comando", "header_description": "Descripción", - "header_avatar": "Avatar", + "header_avatar": "🇺🇸Avatar", "header_item": "Objeto", "header_scene": "Escenario", "header_monster": "Monstruo" }, "index": { "title": "Documentación", - "handbook": "GM Handbook", + "handbook": "🇺🇸GM Handbook", "gacha_mapping": "JSON de mapeo del Gacha" } } -} +} \ No newline at end of file diff --git a/src/main/resources/languages/fr-FR.json b/src/main/resources/languages/fr-FR.json index 094a73ab7c1..5e20237460e 100644 --- a/src/main/resources/languages/fr-FR.json +++ b/src/main/resources/languages/fr-FR.json @@ -246,7 +246,7 @@ "send": "%s %s (niveau %s) ont été ajouté au message.\nContinuez d'ajouter plus d'objets ou utilisez '/sendmail finish' pour envoyer le message.", "invalid_arguments_please_use": "Arguments invalides.\n Veuillez utiliser '/sendmail %s'", "title": "", - "message": "", + "message": "🇺🇸", "sender": "", "arguments": " [quantité] [niveau]", "error": "ERREUR: Stade de construction invalide : %s. Vérifiez la console pour la pile d'appels.", @@ -257,12 +257,12 @@ "description": "Envoie un message au joueur spécifié en tant que Serveur" }, "setConst": { - "range_error": "Constellation level must be between 0 and 6.", - "level_error": "Invalid constellation level.", - "fail": "Failed to set constellation.", - "failed_success": "Constellations for %s have been set to %s. Please reload scene to see changes.", - "success": "Constellations for %s have been set to %s.", - "description": "Sets constellation level for your current active character" + "range_error": "🇺🇸Constellation level must be between 0 and 6.", + "level_error": "🇺🇸Invalid constellation level.", + "fail": "🇺🇸Failed to set constellation.", + "failed_success": "🇺🇸Constellations for %s have been set to %s. Please reload scene to see changes.", + "success": "🇺🇸Constellations for %s have been set to %s.", + "description": "🇺🇸Sets constellation level for your current active character" }, "setFetterLevel": { "range_error": "Le niveau d'affinité doit être compris entre 0 et 10.", @@ -274,7 +274,11 @@ "description": "Définit des propriétes pour votre compte. Des choses comme le godemode peuvent être activés avec cette commande, et le déblocage de l'abysse ainsi que l'avancement du PB.\n\tValues for : godmode | nostamina | unlimitedenergy | abyss | worldlevel | bplevel\n\t(cont.) see PlayerProperty enum for other possible values, of form PROP_MAX_SPRING_VOLUME -> max_spring_volume" }, "setStats": { - "description": "Définit les propriétés de combat de votre personnage actif\n\tValeurs pour : hp | maxhp | def | atk | em | er | crate | cdmg | cdr | heal | heali | shield | defi\n\t(cont.) Bonus de dégât élémentaire: epyro | ecryo | ehydro | egeo | edendro | eelectro | ephys\n\t(cont.) Résistance élémentaire: respyro | rescryo | reshydro | resgeo | resdendro | reselectro | resphys" + "description": "Définit les propriétés de combat de votre personnage actif\n\tValeurs pour : hp | maxhp | def | atk | em | er | crate | cdmg | cdr | heal | heali | shield | defi\n\t(cont.) Bonus de dégât élémentaire: epyro | ecryo | ehydro | egeo | edendro | eelectro | ephys\n\t(cont.) Résistance élémentaire: respyro | rescryo | reshydro | resgeo | resdendro | reselectro | resphys", + "locked_to": "🇺🇸%s locked to %s.", + "locked_for_to": "🇺🇸%s for %s locked to %s.", + "unlocked": "🇺🇸%s unlocked.", + "unlocked_for": "🇺🇸%s for %s unlocked." }, "spawn": { "success": " %s %s sont apparu.", @@ -334,6 +338,10 @@ "invalid_time": "Impossible d'analyser le timestamp.", "description": "Bannis un joueur" }, + "unlockall": { + "success": "🇺🇸Unlocked all open states for %s.", + "description": "🇺🇸Unlocks all open states for a player." + }, "unban": { "success": "Succès.", "failure": "Échec, joueur introuvable.", @@ -349,7 +357,7 @@ }, "records": { "title": "Historique de voeux", - "date": "Date", + "date": "🇺🇸Date", "item": "Objet" } }, @@ -357,22 +365,22 @@ "handbook": { "title": "Manuel GM", "title_commands": "Commandes", - "title_avatars": "Avatars", + "title_avatars": "🇺🇸Avatars", "title_items": "Objets", "title_scenes": "Scènes", "title_monsters": "Monstres", - "header_id": "Id", + "header_id": "🇺🇸Id", "header_command": "Commande", - "header_description": "Description", - "header_avatar": "Avatar", + "header_description": "🇺🇸Description", + "header_avatar": "🇺🇸Avatar", "header_item": "Objet", "header_scene": "Scène", "header_monster": "Monstre" }, "index": { - "title": "Documentation", + "title": "🇺🇸Documentation", "handbook": "Manuel GM", - "gacha_mapping": "Gacha mapping JSON" + "gacha_mapping": "🇺🇸Gacha mapping JSON" } } } \ No newline at end of file diff --git a/src/main/resources/languages/pl-PL.json b/src/main/resources/languages/pl-PL.json index ac89069b315..9e02848cf20 100644 --- a/src/main/resources/languages/pl-PL.json +++ b/src/main/resources/languages/pl-PL.json @@ -257,12 +257,12 @@ "description": "Wyślij wiadomość do gracza jako serwer. Jeśli nie określono celu, wysyła do wszystkich graczy na serwerze." }, "setConst": { - "range_error": "Constellation level must be between 0 and 6.", - "level_error": "Invalid constellation level.", - "fail": "Failed to set constellation.", - "failed_success": "Constellations for %s have been set to %s. Please reload scene to see changes.", - "success": "Constellations for %s have been set to %s.", - "description": "Sets constellation level for your current active character" + "range_error": "🇺🇸Constellation level must be between 0 and 6.", + "level_error": "🇺🇸Invalid constellation level.", + "fail": "🇺🇸Failed to set constellation.", + "failed_success": "🇺🇸Constellations for %s have been set to %s. Please reload scene to see changes.", + "success": "🇺🇸Constellations for %s have been set to %s.", + "description": "🇺🇸Sets constellation level for your current active character" }, "setFetterLevel": { "range_error": "Poziom przyjaźni musi być pomiędzy 0 a 10.", @@ -274,7 +274,11 @@ "description": "Ustaw pewne własności konta, takie jak tryb nieśmiertelności (godmode) czy też zmiana postępu Battle Pass.\n\tMożliwe nazwy własności: godmode | nostamina | unlimitedenergy | abyss | worldlevel | bplevel | ...\n\tTa komenda ma więcej nazw własności, które może otrzymać. Możesz je wszystkie zobaczyć w pliku \"game/props/PlayerProperty.java\".\n\tW tym pliku, przyjmują one formę \"PROP_XXX_YYY_ZZZ\", ale powinieneś je zapisywać jako \"xxx_yyy_zzz\" jeśli chcesz je użyć w tej komendzie." }, "setStats": { - "description": "Ustaw statystykę walki dla obecnie wybranej postaci wybranego gracza.\n\tMożliwe nazwy statystyki: hp | maxhp | def | atk | em | er | crate | cdmg | cdr | heal | heali | shield | defi\n\tDodatkowe obrażenia od żywiołu: epyro | ecryo | ehydro | egeo | edendro | eelectro | ephys\n\tOdporność na żywioł: respyro | rescryo | reshydro | resgeo | resdendro | reselectro | resphys" + "description": "Ustaw statystykę walki dla obecnie wybranej postaci wybranego gracza.\n\tMożliwe nazwy statystyki: hp | maxhp | def | atk | em | er | crate | cdmg | cdr | heal | heali | shield | defi\n\tDodatkowe obrażenia od żywiołu: epyro | ecryo | ehydro | egeo | edendro | eelectro | ephys\n\tOdporność na żywioł: respyro | rescryo | reshydro | resgeo | resdendro | reselectro | resphys", + "locked_to": "🇺🇸%s locked to %s.", + "locked_for_to": "🇺🇸%s for %s locked to %s.", + "unlocked": "🇺🇸%s unlocked.", + "unlocked_for": "🇺🇸%s for %s unlocked." }, "spawn": { "success": "Stworzono %s obiektów o ID %s.", @@ -334,6 +338,10 @@ "invalid_time": "Nieprawidłowy czas bana.", "description": "Zbanuj podanego gracza." }, + "unlockall": { + "success": "🇺🇸Unlocked all open states for %s.", + "description": "🇺🇸Unlocks all open states for a player." + }, "unban": { "success": "Pomyślnie odbanowano podanego gracza.", "failure": "Gracz o podanym ID nie istnieje.", diff --git a/src/main/resources/languages/ro-RO.json b/src/main/resources/languages/ro-RO.json index c0226496cdc..5abb9137690 100644 --- a/src/main/resources/languages/ro-RO.json +++ b/src/main/resources/languages/ro-RO.json @@ -257,12 +257,12 @@ "description": "Trimite un mesaj unui jucător în calitate de server. Dacă este utilizat fără țintă, trimite mesajul către toți jucătorii de pe server." }, "setConst": { - "range_error": "Constellation level must be between 0 and 6.", - "level_error": "Invalid constellation level.", - "fail": "Failed to set constellation.", - "failed_success": "Constellations for %s have been set to %s. Please reload scene to see changes.", - "success": "Constellations for %s have been set to %s.", - "description": "Sets constellation level for your current active character" + "range_error": "🇺🇸Constellation level must be between 0 and 6.", + "level_error": "🇺🇸Invalid constellation level.", + "fail": "🇺🇸Failed to set constellation.", + "failed_success": "🇺🇸Constellations for %s have been set to %s. Please reload scene to see changes.", + "success": "🇺🇸Constellations for %s have been set to %s.", + "description": "🇺🇸Sets constellation level for your current active character" }, "setFetterLevel": { "range_error": "Nivelul Fetter trebuie să fie între 0 și 10.", @@ -274,7 +274,11 @@ "description": "Stabilește proprietățile la nivel de cont. Lucruri precum godmode pot fi activate în acest fel, precum și schimbarea unor lucuri precum etajul abisului deblocat și progresul battle pass.\n\tValori pentru : godmode | nostamina | unlimitedenergy | abyss | worldlevel | bplevel\n\t(cont.) see PlayerProperty enum for other possible values, of form PROP_MAX_SPRING_VOLUME -> max_spring_volume" }, "setStats": { - "description": "Stabilește proprietatea de luptă pentru caracterul activ curent.\n\tValori pentru : hp | maxhp | def | atk | em | er | crate | cdmg | cdr | heal | heali | shield | defi\n\t(cont.) Elemental DMG Bonus: epyro | ecryo | ehydro | egeo | edendro | eelectro | ephys\n\t(cont.) Elemental RES: respyro | rescryo | reshydro | resgeo | resdendro | reselectro | resphys" + "description": "Stabilește proprietatea de luptă pentru caracterul activ curent.\n\tValori pentru : hp | maxhp | def | atk | em | er | crate | cdmg | cdr | heal | heali | shield | defi\n\t(cont.) Elemental DMG Bonus: epyro | ecryo | ehydro | egeo | edendro | eelectro | ephys\n\t(cont.) Elemental RES: respyro | rescryo | reshydro | resgeo | resdendro | reselectro | resphys", + "locked_to": "🇺🇸%s locked to %s.", + "locked_for_to": "🇺🇸%s for %s locked to %s.", + "unlocked": "🇺🇸%s unlocked.", + "unlocked_for": "🇺🇸%s for %s unlocked." }, "spawn": { "success": "A generat %s de %s.", @@ -334,6 +338,10 @@ "invalid_time": "Imposibil de analizat durata.", "description": "Interziceți un jucător" }, + "unlockall": { + "success": "🇺🇸Unlocked all open states for %s.", + "description": "🇺🇸Unlocks all open states for a player." + }, "unban": { "success": "Succes.", "failure": "Eșec, jucătorul nu a fost găsit.", diff --git a/src/main/resources/languages/ru-RU.json b/src/main/resources/languages/ru-RU.json index 67ce3c3ae07..c96cac27919 100644 --- a/src/main/resources/languages/ru-RU.json +++ b/src/main/resources/languages/ru-RU.json @@ -274,7 +274,11 @@ "description": "Задаёт свойства аккаунта. С помощью данной команды может быть включен godmode, а также разблокированы этажи Коридора Бездны и изменён прогресс боевого пропуска.\n\tВозможные значения <св-во>: godmode | nostamina | unlimitedenergy | abyss | worldlevel | bplevel\n\t(прод.) см. перечисление (enum) PlayerProperty для остальных возможных значений, of form PROP_MAX_SPRING_VOLUME -> max_spring_volume" }, "setStats": { - "description": "Задаёт боевые характеристики для активного персонажа\n\tВозможные значения <хар-ка>: hp | maxhp | def | atk | em | er | crate | cdmg | cdr | heal | heali | shield | defi\n\t(прод.) Бонус элементального урона: epyro | ecryo | ehydro | egeo | edendro | eelectro | ephys\n\t(прод.) Элементальное сопротивление: respyro | rescryo | reshydro | resgeo | resdendro | reselectro | resphys" + "description": "Задаёт боевые характеристики для активного персонажа\n\tВозможные значения <хар-ка>: hp | maxhp | def | atk | em | er | crate | cdmg | cdr | heal | heali | shield | defi\n\t(прод.) Бонус элементального урона: epyro | ecryo | ehydro | egeo | edendro | eelectro | ephys\n\t(прод.) Элементальное сопротивление: respyro | rescryo | reshydro | resgeo | resdendro | reselectro | resphys", + "locked_to": "🇺🇸%s locked to %s.", + "locked_for_to": "🇺🇸%s for %s locked to %s.", + "unlocked": "🇺🇸%s unlocked.", + "unlocked_for": "🇺🇸%s for %s unlocked." }, "spawn": { "success": "Заспавнено %s %s.", @@ -379,4 +383,4 @@ "gacha_mapping": "Мапирование системы гача в JSON" } } -} +} \ No newline at end of file diff --git a/src/main/resources/languages/zh-CN.json b/src/main/resources/languages/zh-CN.json index 60da64f8d4d..be4828d6a40 100644 --- a/src/main/resources/languages/zh-CN.json +++ b/src/main/resources/languages/zh-CN.json @@ -274,7 +274,11 @@ "description": "设置账号的状态。比如可以通过此命令启用 godmode,也可以解锁深渊或更改纪行等级\n\t可更改的状态列表:godmode(上帝模式)|nostamina(无限体力)|unlimitedenergy(无限能量)|abyss(深渊)|worldlevel(世界等级)|bplevel(纪行等级)\n查看 PlayerProperty enum 以获得其他数值,格式为 PROP_MAX_SPRING_VOLUME -> max_spring_volume" }, "setStats": { - "description": "设置当前角色的属性\n\t可更改的属性列表:hp(生命值)|maxhp(最大生命值)|def(防御力)|atk(攻击力)|em(元素精通)|er(元素充能效率)|crate(暴击率)|cdmg(暴击伤害)|cdr(冷却缩减)|heal(治疗加成)|heali(受治疗加成)|shield(护盾强效)|defi(无视防御)\n元素增伤:epyro(火)|ecryo(冰)|ehydro(水)|egeo(岩)|edendro(草)|eelectro(雷)|ephys(物理)\n元素抗性:respyro(火)|rescryo(冰)|reshydro(水)|resgeo(岩)|resdendro(草)|reselectro(雷)|resphys(物理)" + "description": "设置当前角色的属性\n\t可更改的属性列表:hp(生命值)|maxhp(最大生命值)|def(防御力)|atk(攻击力)|em(元素精通)|er(元素充能效率)|crate(暴击率)|cdmg(暴击伤害)|cdr(冷却缩减)|heal(治疗加成)|heali(受治疗加成)|shield(护盾强效)|defi(无视防御)\n元素增伤:epyro(火)|ecryo(冰)|ehydro(水)|egeo(岩)|edendro(草)|eelectro(雷)|ephys(物理)\n元素抗性:respyro(火)|rescryo(冰)|reshydro(水)|resgeo(岩)|resdendro(草)|reselectro(雷)|resphys(物理)", + "locked_to": "🇺🇸%s locked to %s.", + "locked_for_to": "🇺🇸%s for %s locked to %s.", + "unlocked": "🇺🇸%s unlocked.", + "unlocked_for": "🇺🇸%s for %s unlocked." }, "spawn": { "success": "已生成 %s 个 %s。", @@ -334,6 +338,10 @@ "invalid_time": "无法解析时间戳。", "description": "封禁玩家" }, + "unlockall": { + "success": "🇺🇸Unlocked all open states for %s.", + "description": "🇺🇸Unlocks all open states for a player." + }, "unban": { "success": "成功取消玩家的封禁。", "failure": "取消玩家的封禁失败,因为玩家不存在。", @@ -375,4 +383,4 @@ "gacha_mapping": "祈愿物品映射JSON" } } -} +} \ No newline at end of file diff --git a/src/main/resources/languages/zh-TW.json b/src/main/resources/languages/zh-TW.json index 36a9e87f63e..70a36158421 100644 --- a/src/main/resources/languages/zh-TW.json +++ b/src/main/resources/languages/zh-TW.json @@ -274,7 +274,11 @@ "description": "設定帳號屬性。 比如可以通過此命令啟用無敵,也可以解鎖深淵或更改紀行等級。\n\t可更改的屬性列表: godmode(無敵)|nostamina(無限體力)|unlimitedenergy(無限元素能量)|abyss(深淵螺旋)|worldlevel(世界等級)|bplevel(紀行等級)\n\t(cont.) `有關其他可能的數值,請參閱 PlayerProperty 列舉。 (範例 PROP_MAX_SPRING_VOLUME -> max_spring_volume)`" }, "setStats": { - "description": "設定當前角色的數據類型。\n\t可使用的數據類型:hp (生命值)| maxhp (最大生命值) | def(防禦力) | atk (攻擊力)| em (元素精通) | er (元素充能效率) | crate(暴擊率) | cdmg (暴擊傷害)| cdr (冷卻縮減) | heal(治療加成)| heali (受治療加成)| shield (護盾強效)| defi (無視防禦)\n\t(cont.) 元素增傷類:epyro (火傷) | ecryo (冰傷) | ehydro (水傷) | egeo (岩傷) | edendro (草傷) | eelectro (雷傷) | ephys (物傷)(cont.) 元素減傷類:respyro (火抗) | rescryo (冰抗) | reshydro (水抗) | resgeo (岩抗) | resdendro (草抗) | reselectro (雷抗) | resphys (物抗)" + "description": "設定當前角色的數據類型。\n\t可使用的數據類型:hp (生命值)| maxhp (最大生命值) | def(防禦力) | atk (攻擊力)| em (元素精通) | er (元素充能效率) | crate(暴擊率) | cdmg (暴擊傷害)| cdr (冷卻縮減) | heal(治療加成)| heali (受治療加成)| shield (護盾強效)| defi (無視防禦)\n\t(cont.) 元素增傷類:epyro (火傷) | ecryo (冰傷) | ehydro (水傷) | egeo (岩傷) | edendro (草傷) | eelectro (雷傷) | ephys (物傷)(cont.) 元素減傷類:respyro (火抗) | rescryo (冰抗) | reshydro (水抗) | resgeo (岩抗) | resdendro (草抗) | reselectro (雷抗) | resphys (物抗)", + "locked_to": "🇺🇸%s locked to %s.", + "locked_for_to": "🇺🇸%s for %s locked to %s.", + "unlocked": "🇺🇸%s unlocked.", + "unlocked_for": "🇺🇸%s for %s unlocked." }, "spawn": { "success": "已生成 %s 個 %s。", @@ -334,6 +338,10 @@ "invalid_time": "無效的時間戳。", "description": "停權指定玩家。" }, + "unlockall": { + "success": "🇺🇸Unlocked all open states for %s.", + "description": "🇺🇸Unlocks all open states for a player." + }, "unban": { "success": "撤銷停權成功。", "failure": "撤銷停權失敗,玩家帳號不存在。", @@ -355,7 +363,7 @@ }, "documentation": { "handbook": { - "title": "GM Handbook", + "title": "🇺🇸GM Handbook", "title_commands": "指令", "title_avatars": "角色", "title_items": "道具", @@ -371,8 +379,8 @@ }, "index": { "title": "文件", - "handbook": "GM Handbook", + "handbook": "🇺🇸GM Handbook", "gacha_mapping": "祈願物品映射到JSON上" } } -} +} \ No newline at end of file