diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 000000000..0da240716 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,40 @@ +// For format details, see https://aka.ms/devcontainer.json. For config options, see the +// README at: https://github.com/devcontainers/templates/tree/main/src/javascript-node +{ + "name": "RustPlusPlus Dev Container", + "image": "mcr.microsoft.com/devcontainers/javascript-node:22", + + // Features to add to the dev container. More info: https://containers.dev/features. + "features": { + "ghcr.io/devcontainers/features/node:1": { + "version": "22" + }, + "ghcr.io/devcontainers/features/git:1": {}, + "ghcr.io/devcontainers/features/docker-in-docker:2": {} + }, + + // Install npm packages and set up the development environment + "postCreateCommand": "npm install", + + // Setup VS Code extensions + "customizations": { + "vscode": { + "extensions": [ + "dbaeumer.vscode-eslint", + "esbenp.prettier-vscode", + "ms-azuretools.vscode-docker" + ] + } + }, + + "remoteEnv": { + "RPP_LANGUAGE": "en", + "RPP_POLLING_INTERVAL": "10000", + "RPP_LOG_CALL_STACK": "true", + "RPP_RECONNECT_INTERVAL": "15000", + "RPP_DISCORD_USERNAME": "RustPlusPlus", + "RPP_DISCORD_CLIENT_ID": "", + "RPP_DISCORD_TOKEN": "", + "RPP_NEED_ADMIN_PRIVILEGES": "false" + } +} diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 000000000..e97e4d93d --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,26 @@ +--- +name: Bug report +about: Create a report to help us improve +title: '' +labels: '' +assignees: 'bug' + +--- + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior: + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**Environment (please complete the following information):** + - Hosting OS: + - Node Version (node -v): + - NPM Version (npm -v): + - Bot Version (git log -1): \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 000000000..da3909363 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,20 @@ +--- +name: Feature request +about: Suggest an idea for this project +title: '' +labels: '' +assignees: 'enhancement' + +--- + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here. diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 000000000..66ac4e879 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,26 @@ +# To get started with Dependabot version updates, you'll need to specify which +# package ecosystems to update and where the package manifests are located. +# Please see the documentation for all configuration options: +# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file + +version: 2 +updates: + - package-ecosystem: "npm" # See documentation for possible values + directory: "/" # Location of package manifests + schedule: + interval: "weekly" + + - package-ecosystem: "docker" # See documentation for possible values + directory: "/" # Location of package manifests + schedule: + interval: "weekly" + + - package-ecosystem: "github-actions" # See documentation for possible values + directory: "/" # Location of package manifests + schedule: + interval: "weekly" + + - package-ecosystem: "devcontainers" + directory: "/" + schedule: + interval: weekly diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 8eefaff31..f2f56d058 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -8,10 +8,10 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - node: [ 14, 16, 18 ] + node: [18, 20, 22 ] steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 + - uses: actions/checkout@v4.2.1 + - uses: actions/setup-node@v4.1.0 with: node-version: ${{ matrix.node }} cache: 'npm' diff --git a/docs/commands.md b/docs/commands.md index 9dfd6ab22..a24806097 100644 --- a/docs/commands.md +++ b/docs/commands.md @@ -22,6 +22,7 @@ Slash Command | Description [**/map**](commands.md#map) | Get the currently connected server map image. [**/market**](commands.md#market) | Operations for In-Game Vending Machines. [**/players**](commands.md#players) | Get player/players information based on battlemetrics. +[**/raid**](commands.md#raid) | Display the raid costs for an item. [**/recycle**](commands.md#recycle) | Display the output of recycling an item. [**/research**](commands.md#research) | Display the cost to research an item. [**/reset**](commands.md#reset) | Reset Discord channels. @@ -224,6 +225,17 @@ Subcommand | Options | Description | Required ![Discord Slash Command players specific user Image](images/slash_commands/players_specific_user.png) +## **/raid** + +> **Display the raid costs for an item.** + +Subcommand | Options | Description | Required +---------- | ------- | ----------- | -------- +  | `name` | The name of the item to raid. | `False` +  | `id` | The id of the item to raid. | `False` + +![Discord Slash Command raid Image](images/slash_commands/raid.png) + ## **/recycle** > **Display the output of recycling an item.** diff --git a/docs/images/slash_commands/raid.png b/docs/images/slash_commands/raid.png new file mode 100644 index 000000000..6295ea1bc Binary files /dev/null and b/docs/images/slash_commands/raid.png differ diff --git a/src/commands/durability.js b/src/commands/durability.js new file mode 100644 index 000000000..d6510bdde --- /dev/null +++ b/src/commands/durability.js @@ -0,0 +1,155 @@ +/* + Copyright (C) 2023 Alexander Emanuelsson (alexemanuelol) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + https://github.com/alexemanuelol/rustplusplus + +*/ + +const Builder = require('@discordjs/builders'); + +const DiscordEmbeds = require('../discordTools/discordEmbeds.js'); +const DiscordMessages = require('../discordTools/discordMessages.js'); + +module.exports = { + name: 'raid', + + getData(client, guildId) { + return new Builder.SlashCommandBuilder() + .setName('raid') + .setDescription(client.intlGet(guildId, 'commandsRaidDesc')) + .addStringOption(option => option + .setName('name') + .setDescription(client.intlGet(guildId, 'theNameOfTheItem')) + .setRequired(false)) + .addStringOption(option => option + .setName('id') + .setDescription(client.intlGet(guildId, 'theIdOfTheItem')) + .setRequired(false)); + }, + + + + /** + * Group durability data by group and toolId. + * @param {array} data The array of durability data objects. + * @return {object} The grouped durability data. + */ + groupDurabilityData(client, data) { + const groupedData = {}; + + for (const item of data) { + if (item.which === 'soft') continue; + + if (!groupedData[item.group]) { + groupedData[item.group] = {}; + } + + if (!groupedData[item.group][item.toolId]) { + groupedData[item.group][item.toolId] = []; + } + + groupedData[item.group][item.toolId].push({ + ...item, + 'itemName': client.items.getName(item.toolId) + }); + } + + return groupedData; + }, + + getDurabilityData(raidItemName, raidItemId, client, guildId) { + let itemId = null; + if (raidItemName !== null) { + let item = null + if (!item) { + item = client.rustlabs.getClosestOtherNameByName(raidItemName); + } + + if (!item) { + item = client.items.getClosestItemIdByName(raidItemName); + if(item !== null) { + item = client.items.getName(item); + } + } + + if (!item) { + item = client.rustlabs.getClosestBuildingBlockNameByName(raidItemName); + } + + if (item === null) { + return null; + } + else { + itemId = item; + } + } + else if (raidItemId !== null) { + if (client.items.itemExist(raidItemId)) { + itemId = raidItemId; + } + else { + return null; + } + } + const itemName = client.items.getName(itemId); + + const raidDetails = client.rustlabs.getDurabilityDetailsByName(raidItemName); + if (raidDetails === null) { + return null; + } + + raidDetails[3] = this.groupDurabilityData(client, raidDetails[3]); + return raidDetails; + }, + + async execute(client, interaction) { + const guildId = interaction.guildId; + + const verifyId = Math.floor(100000 + Math.random() * 900000); + client.logInteraction(interaction, verifyId, 'slashCommand'); + + if (!await client.validatePermissions(interaction)) return; + await interaction.deferReply({ ephemeral: true }); + + const raidItemName = interaction.options.getString('name'); + const raidItemId = interaction.options.getString('id'); + if (raidItemName === null && raidItemId === null) { + const str = client.intlGet(guildId, 'noNameIdGiven'); + await client.interactionEditReply(interaction, DiscordEmbeds.getActionInfoEmbed(1, str)); + client.log(client.intlGet(guildId, 'warningCap'), str); + return null; + } + + client.log(client.intlGet(null, 'infoCap'), client.intlGet(null, 'slashCommandValueChange', { + id: `${verifyId}`, + value: `${raidItemName} ${raidItemId}` + })); + + const raidDetails = this.getDurabilityData(raidItemName, raidItemId, client, interaction); + + if (raidDetails === null) { + const str = client.intlGet(guildId, 'noItemWithNameFound', { + name: raidItemName + }); + await client.interactionEditReply(interaction, DiscordEmbeds.getActionInfoEmbed(1, str)); + client.log(client.intlGet(guildId, 'warningCap'), str); + return; + } + + await DiscordMessages.sendRaidMessage(interaction, raidDetails); + client.log(client.intlGet(null, 'infoCap'), client.intlGet(guildId, 'commandsRaidDesc')); + }, +}; diff --git a/src/commands/market.js b/src/commands/market.js index cbad557c9..5a14a3c8c 100644 --- a/src/commands/market.js +++ b/src/commands/market.js @@ -1,5 +1,6 @@ /* Copyright (C) 2022 Alexander Emanuelsson (alexemanuelol) + Copyright (C) 2022 René Renken (faithix) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -89,7 +90,22 @@ module.exports = { .setRequired(false))) .addSubcommand(subcommand => subcommand .setName('list') - .setDescription(client.intlGet(guildId, 'commandsMarketListDesc'))); + .setDescription(client.intlGet(guildId, 'commandsMarketListDesc'))) + .addSubcommand(subcommand => subcommand + .setName('blacklist') + .setDescription(client.intlGet(guildId, 'commandsMarketBlaclistDesc')) + .addStringOption(option => option + .setName('choice') + .setDescription(client.intlGet(guildId, 'commandsAddOrRemove')) + .setRequired(true) + .addChoices( + { name: client.intlGet(guildId, 'add'), value: 'add' }, + { name: client.intlGet(guildId, 'remove'), value: 'remove' }, + { name: client.intlGet(guildId, 'show'), value: 'show' })) + .addStringOption(option => option + .setName('name') + .setDescription(client.intlGet(guildId, 'theNameOfTheVendingMachine')) + .setRequired(false))); }, async execute(client, interaction) { @@ -406,6 +422,80 @@ module.exports = { client.intlGet(interaction.guildId, 'showingSubscriptionList')); } break; + case 'blacklist': { + const choice = interaction.options.getString('choice'); + const name = interaction.options.getString('name'); + + if (choice === 'add' && name !== null) { + if (instance.marketBlacklist.includes(name)) { + const str = client.intlGet(interaction.guildId, 'alreadyBlacklisted', { + name: name + }); + await client.interactionEditReply(interaction, DiscordEmbeds.getActionInfoEmbed(1, str)); + rustplus.log(client.intlGet(interaction.guildId, 'warningCap'), str); + } + else { + instance.marketBlacklist.push(name); + client.setInstance(interaction.guildId, instance); + + const str = client.intlGet(interaction.guildId, 'justBlacklisted', { + name: name + }); + await client.interactionEditReply(interaction, DiscordEmbeds.getActionInfoEmbed(0, str)); + rustplus.log(client.intlGet(interaction.guildId, 'infoCap'), str); + } + } + else if (choice === 'remove' && name !== null) { + if (instance.marketBlacklist.includes(name)) { + instance.marketBlacklist = instance.marketBlacklist.filter(e => e !== name); + client.setInstance(interaction.guildId, instance); + + const str = client.intlGet(interaction.guildId, 'removedBlacklist', { + name: name + }); + await client.interactionEditReply(interaction, DiscordEmbeds.getActionInfoEmbed(0, str)); + rustplus.log(client.intlGet(interaction.guildId, 'infoCap'), str); + } + else { + const str = client.intlGet(interaction.guildId, 'notExistInBlacklist', { + name: name + }); + await client.interactionEditReply(interaction, DiscordEmbeds.getActionInfoEmbed(1, str)); + rustplus.log(client.intlGet(interaction.guildId, 'warningCap'), str); + } + } + else if (choice === 'show') { + let names = ''; + for (const name of instance.marketBlacklist) { + names += `\`${name}\`\n`; + } + + await client.interactionEditReply(interaction, { + embeds: [DiscordEmbeds.getEmbed({ + color: Constants.COLOR_DEFAULT, + title: client.intlGet(interaction.guildId, 'blacklist'), + footer: { text: instance.serverList[rustplus.serverId].title }, + description: names === '' ? '\u200B' : names + })], + ephemeral: true + }); + + rustplus.log(client.intlGet(interaction.guildId, 'infoCap'), + client.intlGet(interaction.guildId, 'showingBlacklist')); + } + else if (choice === null || name === null) { + const str = client.intlGet(interaction.guildId, 'noNameGiven'); + await client.interactionEditReply(interaction, DiscordEmbeds.getActionInfoEmbed(1, str)); + rustplus.log(client.intlGet(interaction.guildId, 'warningCap'), str); + return; + } + + client.log(client.intlGet(null, 'infoCap'), client.intlGet(null, 'slashCommandValueChange', { + id: `${verifyId}`, + value: `blacklist, ${choice}, ${name}` + })); + } break; + default: { } break; diff --git a/src/discordTools/discordEmbeds.js b/src/discordTools/discordEmbeds.js index c47e46359..cf989e60c 100644 --- a/src/discordTools/discordEmbeds.js +++ b/src/discordTools/discordEmbeds.js @@ -1121,6 +1121,36 @@ module.exports = { }); }, + getRaidEmbed: function (guildId, raidDetails) { + const raidCosts = { + name: '', + time: '', + sulfur: '' + }; + + const sortedItems = Object.values(raidDetails[3].explosive).sort((a, b) => { + const sulfurA = a[0].sulfur === null ? Infinity : Number(a[0].sulfur); + const sulfurB = b[0].sulfur === null ? Infinity : Number(b[0].sulfur); + return sulfurA - sulfurB; + }); + for (const item of sortedItems) { + raidCosts.name += `${item[0].itemName}\n`; + raidCosts.time += `${item[0].timeString} (${item[0].quantity})\n`; + raidCosts.sulfur += `${item[0].sulfur}\n`; + } + + return module.exports.getEmbed({ + title: `${raidDetails[1]}`, + color: Constants.COLOR_DEFAULT, + timestamp: true, + fields: [ + { name: Client.client.intlGet(guildId, 'name'), value: raidCosts.name.trim(), inline: true }, + { name: Client.client.intlGet(guildId, 'time'), value: raidCosts.time.trim(), inline: true }, + { name: Client.client.intlGet(guildId, 'sulfur'), value: raidCosts.sulfur.trim(), inline: true } + ] + }); + }, + getResearchEmbed: function (guildId, researchDetails) { let typeString = '', scrapString = ''; if (researchDetails[2].researchTable !== null) { diff --git a/src/discordTools/discordMessages.js b/src/discordTools/discordMessages.js index dcc2e0ee5..dbace5ab1 100644 --- a/src/discordTools/discordMessages.js +++ b/src/discordTools/discordMessages.js @@ -560,6 +560,15 @@ module.exports = { await Client.client.interactionEditReply(interaction, content); }, + sendRaidMessage: async function (interaction, raidDetails) { + const content = { + embeds: [DiscordEmbeds.getRaidEmbed(interaction.guildId, raidDetails)], + ephemeral: true + } + + await Client.client.interactionEditReply(interaction, content); + }, + sendResearchMessage: async function (interaction, researchDetails) { const content = { embeds: [DiscordEmbeds.getResearchEmbed(interaction.guildId, researchDetails)], diff --git a/src/external/process_rustlabs.js b/src/external/process_rustlabs.js index c12a68b40..e7b5f7a86 100644 --- a/src/external/process_rustlabs.js +++ b/src/external/process_rustlabs.js @@ -594,7 +594,10 @@ function processItemDurability(rustlabsName, shortname, name, data, type = 'item } if (toolShortname === null || toolName === null) exit(); toolId = Object.keys(ITEMS).find(e => ITEMS[e].shortname === toolShortname && ITEMS[e].name === toolName); - if (!toolId) exit(); + if (!toolId) { + console.error(`Tool ID not found for ${toolShortname} - ${toolName}`); + continue; // Skip this iteration and continue with the next match + } /* Caption in tool name */ let captionInTool = null; diff --git a/src/handlers/discordCommandHandler.js b/src/handlers/discordCommandHandler.js index baf9f6bc4..89f4053cb 100644 --- a/src/handlers/discordCommandHandler.js +++ b/src/handlers/discordCommandHandler.js @@ -204,6 +204,10 @@ module.exports = { commandLowerCase === `${prefix}${client.intlGet(guildId, 'commandSyntaxTravelingVendor')}`) { response = rustplus.getCommandTravelingVendor(); } + else if (commandLowerCase === `${prefix}${client.intlGet('en', 'commandSyntaxRaid')}` || + commandLowerCase === `${prefix}${client.intlGet(guildId, 'commandSyntaxRaid')}`) { + response = rustplus.getCommandRaidCost(command); + } else { /* Smart Switches/ Group Switches are not currently supported through discord. */ return false; diff --git a/src/handlers/inGameCommandHandler.js b/src/handlers/inGameCommandHandler.js index 8d606ef74..6ea2d1699 100644 --- a/src/handlers/inGameCommandHandler.js +++ b/src/handlers/inGameCommandHandler.js @@ -211,6 +211,10 @@ module.exports = { commandLowerCase === `${prefix}${client.intlGet(guildId, 'commandSyntaxTravelingVendor')}`) { rustplus.sendInGameMessage(rustplus.getCommandTravelingVendor()); } + else if (commandLowerCase.startsWith(`${prefix}${client.intlGet('en', 'commandSyntaxRaid')}`) || + commandLowerCase.startsWith(`${prefix}${client.intlGet(guildId, 'commandSyntaxRaid')}`)) { + rustplus.sendInGameMessage(rustplus.getCommandRaidCost(command)); + } else { /* Maybe a custom command? */ diff --git a/src/languages/en.json b/src/languages/en.json index bb5fb961d..7399eab14 100644 --- a/src/languages/en.json +++ b/src/languages/en.json @@ -3,6 +3,7 @@ "abandonedCabins": "Abandoned Cabins", "abandonedMilitaryBase": "Abandoned Military Base", "abandonedSupermarket": "Abandoned Supermarket", + "add": "Add", "addPlayerCap": "ADD PLAYER", "addSwitchCap": "ADD SWITCH", "afkCap": "AFK", @@ -16,6 +17,7 @@ "aliases": "Aliases", "all": "all", "allTeammatesAreDead": "All your teammates are dead.", + "alreadyBlacklisted": "Vending Machine {name} is already blacklisted.", "alreadySubscribedToItem": "Already subscribed to item {name}.", "ampersand": "Ampersand", "andMorePlayers": "... and {number} more players.", @@ -142,6 +144,7 @@ "commandSyntaxPlayers": "players", "commandSyntaxPop": "pop", "commandSyntaxProx": "prox", + "commandSyntaxRaid": "raid", "commandSyntaxRecycle": "recycle", "commandSyntaxRemove": "remove", "commandSyntaxResearch": "research", @@ -168,6 +171,7 @@ "commandSyntaxUptime": "uptime", "commandSyntaxWipe": "wipe", "commandSyntaxWood": "wood", + "commandsAddOrRemove": "Add or Remove a Vending Machine.", "commandsAlarmDesc": "Operations on Smart Alarms.", "commandsAlarmEditDesc": "Edit the properties of a Smart Alarm.", "commandsAlarmEditIdDesc": "The ID of the Smart Alarm.", @@ -209,6 +213,7 @@ "commandsMapDesc": "Get the currently connected server map image.", "commandsMapMarkersDesc": "Get the map including markers.", "commandsMapMonumentsDesc": "Get the map including monument names.", + "commandsMarketBlaclistDesc": "Add or Remove a Vending Machine Name to the Blacklist.", "commandsMarketDesc": "Operations for In-Game Vending Machines.", "commandsMarketListDesc": "Display the subscription list.", "commandsMarketOrderDesc": "The order type.", @@ -225,6 +230,7 @@ "commandsRecycleQuantityDesc": "The quantity of items to recycle.", "commandsRecycleRecyclerTypeDesc": "The recycler type (recycler, shredder, safe-zone-recycler).", "commandsResearchDesc": "Display the cost to research an item.", + "commandsRaidDesc": "Display the cost to destroy an item.", "commandsResetAlarmsDesc": "Reset alarms channel.", "commandsResetDesc": "Reset Discord channels.", "commandsResetInformationDesc": "Reset information channel.", @@ -297,6 +303,7 @@ "couldNotFindPlayerId": "Could not find player with id {id}.", "couldNotFindRecycleDetails": "Could not find recycle details for {name}.", "couldNotFindResearchDetails": "Could not find research details for {name}.", + "couldNotFindRaidDetails": "Could not find raid details for {name}.", "couldNotFindRole": "Could not find role: {roleId}", "couldNotFindStackDetails": "Could not find stack details for {name}.", "couldNotFindTeammate": "Could not find teammate: {name}.", @@ -429,6 +436,7 @@ "itemAvailableInVendingMachine": "{items} just became available in a Vending Machine at [{location}].", "itemAvailableNotifyInGameSetting": "When an item from the subscription list becomes available in a Vending Machine, notify In-Game?", "junkyard": "Junkyard", + "justBlacklisted": "Vending Machine {name} just got blacklisted.", "justSubscribedToItem": "Just subscribed to item {name}.", "languageCode": "Language code: {code}", "languageLangNotSupported": "The language {language} is not supported.", @@ -500,6 +508,7 @@ "noItemFound": "Item could not be found in any Vending Machines...", "noItemWithIdFound": "No item with id {id} could be found.", "noItemWithNameFound": "No item with name {name} could be found.", + "noNameGiven": "No 'name' was given.", "noNameIdGiven": "No 'name' or 'id' was given.", "noOneIsAfk": "No one is AFK.", "noOneIsOffline": "No one is offline.", @@ -519,6 +528,7 @@ "notAValidOrderType": "{order} is not a valid order type.", "notActive": "Not active.", "notConnectedToRustServer": "Not currently connected to a rust server.", + "notExistInBlacklist": "Vending Machine {name} does not exist in blacklist.", "notExistInSubscription": "Item {name} does not exist in subscription list.", "notFoundCap": "NOT FOUND", "notPartOfRole": "You are not part of the {role} role, therefore you can't run bot commands.", @@ -585,6 +595,8 @@ "recycleCap": "RECYCLE", "recycler": "Recycler", "remain": "left", + "remove": "Remove", + "removedBlacklist": "Vending Machine {name} got removed from the blacklist.", "removePlayerCap": "REMOVE PLAYER", "removeSwitchCap": "REMOVE SWITCH", "removedSubscribeItem": "Item {name} have been removed from subscription.", @@ -635,6 +647,7 @@ "shouldSmartAlarmNotifyNotConnectedSetting": "Should Smart Alarms notify even if they are not setup on the connected rust server?", "shouldSmartAlarmsNotifyInGameSetting": "Should Smart Alarms notify In-Game?", "shouldSmartSwitchNotifyInGameWhenChangedFromDiscord": "Should Smart Switches and Smart Switch Groups notify In-Game when they are changed from discord?", + "show": "Show", "showingBlacklist": "Showing the blacklist.", "showingSubscriptionList": "Showing the subscription list.", "shredder": "Shredder", @@ -682,6 +695,7 @@ "subscribeToChangesBattlemetrics": "Subscribe to different changes on Battlemetrics.", "subscriptionList": "Subscription list", "subscriptionListEmpty": "Item subscription list is empty.", + "sulfur": "Sulfur", "sulfurQuarry": "Sulfur Quarry", "switches": "Switches", "teamMember": "Team Member", @@ -690,6 +704,7 @@ "theIdOfTheItem": "The id of the item.", "theNameOfTheItem": "The name of the item.", "theNameOfThePlayer": "The name of the player.", + "theNameOfTheVendingMachine": "The name of the vending machine.", "three": "Three", "tilde": "Tilde", "time": "Time", diff --git a/src/languages/zh.json b/src/languages/zh.json new file mode 100644 index 000000000..fa6a757b8 --- /dev/null +++ b/src/languages/zh.json @@ -0,0 +1,790 @@ +{ + "24HoursInGameTimePassed": "游戏时间已经过去24小时。", + "abandonedCabins": "废弃的小屋", + "abandonedMilitaryBase": "废弃的军事基地", + "abandonedSupermarket": "废弃的超市", + "addPlayerCap": "添加玩家", + "addSwitchCap": "添加开关", + "afkCap": "暂离", + "airfield": "飞机场", + "alarmHaveNotBeenTriggeredYet": "警报 {alarm} 还未触发。", + "alias": "别名", + "aliasAlreadyExist": "别名已存在。", + "aliasIndexCouldNotBeFound": "找不到别名索引。", + "aliasWasAdded": "已添加别名。", + "aliasWasRemoved": "已移除别名。", + "aliases": "别名", + "all": "全部", + "allTeammatesAreDead": "你的所有队友都已死亡。", + "alreadySubscribedToItem": "已订阅物品 {name}。", + "ampersand": "和号", + "andMorePlayers": "...和 {number} 更多玩家。", + "any": "任何", + "apostrophe": "撇号", + "arcticResearchBase": "北极研究基地", + "asterisk": "星号", + "asteriskCctvDesc": "*表示你需要一个对于每个地图都不同的数字代码", + "atLocation": "在 {location}。", + "atSign": "在标志", + "autoDayCap": "自动-白天", + "autoNightCap": "自动-夜晚", + "autoOffAnyOnlineCap": "自动关闭-任何在线", + "autoOffCap": "自动关闭", + "autoOffProximityCap": "自动关闭-邻近", + "autoOnAnyOnlineCap": "自动开启-任何在线", + "autoOnCap": "自动开启", + "autoOnProximityCap": "自动开启-邻近", + "autoSettingCap": "自动设置:", + "automaticallyTurnBackOnOff": "自动在 {time} 后将 {status}。", + "automaticallyTurningBackOnOff": "自动将 {device} 调回 {status}。", + "autoturret": "自动炮塔", + "badGateway": "错误网关:{error}", + "banditCamp": "强盗营地", + "baseIsUnderAttack": "你的基地正在受到攻击!", + "battlemetricsApiRequestFailed": "Battlemetrics API 请求失败:{api_call}。", + "battlemetricsCap": "战斗指标", + "battlemetricsFailedToUpdate": "Battlemetrics 服务器 {server} 更新失败。", + "battlemetricsGlobalLoginCap": "全球登录", + "battlemetricsGlobalLogoutCap": "全球注销", + "battlemetricsGlobalNameChangesCap": "全球名称更改", + "battlemetricsId": "BattlemetricsID", + "battlemetricsIdAndNameMissing": "Battlemetrics 实例缺少 id 和名称。", + "battlemetricsInstanceCouldNotBeFound": "无法找到 ID 为 {id} 的 Battlemetrics 实例。", + "battlemetricsOnlinePlayers": "Battlemetrics 在线玩家", + "battlemetricsPlayersLogin": "Battlemetrics 玩家登录", + "battlemetricsPlayersLogout": "Battlemetrics 玩家注销", + "battlemetricsPlayersNameChanged": "Battlemetrics 玩家名称已更改", + "battlemetricsServerNameChanged": "Battlemetrics 服务器名称已更改", + "battlemetricsServerNameChangesCap": "服务器名称更改", + "battlemetricsTrackerNameChangesCap": "跟踪器名称更改", + "battlemetricsTrackerPlayerNameChanged": "Battlemetrics 跟踪器玩家名称已更改", + "blacklist": "黑名单", + "boomBox": "爆炸箱", + "bot": "机器人", + "broadcaster": "广播员", + "buttonValueChange": "按钮交互 - 验证 ID: {id}, 值: {value}。", + "buy": "购买", + "calculated": "计算的", + "cargoAt": "在 {location}。", + "cargoLeavingMapAt": "货船将在 {location} 离开地图。", + "cargoLocatedAt": "货船位于 {location}。", + "cargoNotCurrentlyOnMap": "货船当前不在地图上。", + "cargoShipDetectedSetting": "当发现货船时,发送通知。", + "cargoShipDockingAtHarbor": "货船刚刚停靠在港口,位置是 {location}", + "cargoShipDockingAtHarborSetting": "当货船停靠在港口时,发送通知。", + "cargoShipEgressSetting": "当货船进入退出阶段时,发送通知。", + "cargoShipEntersEgressStage": "货船应该位于退出阶段,位置是 {location}。", + "cargoShipEntersMap": "货船从 {location} 进入地图。", + "cargoShipLeftHarbor": "货船刚刚离开了港口,位置是 {location}", + "cargoShipLeftMap": "货船刚刚离开了地图,位置是 {location}。", + "cargoShipLeftSetting": "当货船离开地图时,发送通知。", + "cargoShipLocated": "货船位于 {location}。", + "cargoship": "货船", + "ceilingLight": "天花板灯", + "channelNameActivity": "活动", + "channelNameAlarms": "警报", + "channelNameCommands": "命令", + "channelNameEvents": "事件", + "channelNameInformation": "信息", + "channelNameServers": "服务器", + "channelNameSettings": "设置", + "channelNameStorageMonitors": "存储监控", + "channelNameSwitchGroups": "开关组", + "channelNameSwitches": "开关", + "channelNameTeamchat": "团队聊天", + "channelNameTrackers": "追踪器", + "chinook47": "支奴干 47", + "chinook47DetectedSetting": "检测到支奴干 47 进入地图时发送通知。", + "chinook47EntersMap": "支奴干 47 从 {location} 进入地图以投放锁定箱。", + "chinook47LeftMap": "支奴干 47 在 {location} 离开地图。", + "chinook47Located": "支奴干 47 位于 {location}。", + "chinook47NotOnMap": "支奴干 47 当前不在地图上。", + "christmasLights": "圣诞灯", + "circumflex": "抑扬符", + "clanTag": "氏族标签", + "codes": "代码", + "colon": "冒号", + "comma": "逗号", + "commandCap": "命令", + "commandDelaySetting": "应该有命令延迟吗?多长时间?", + "commandNotPossibleDiscord": "命令无法通过 Discord 执行。", + "commandSyntaxAdd": "添加", + "commandSyntaxAfk": "暂离", + "commandSyntaxAlive": "存活", + "commandSyntaxArmored": "装甲", + "commandSyntaxCargo": "货船", + "commandSyntaxChinook": "支奴干", + "commandSyntaxConnection": "连接", + "commandSyntaxConnections": "连接", + "commandSyntaxCraft": "制作", + "commandSyntaxDeath": "死亡", + "commandSyntaxDeaths": "死亡", + "commandSyntaxDecay": "衰变", + "commandSyntaxDespawn": "消失", + "commandSyntaxEvents": "事件", + "commandSyntaxHeli": "直升机", + "commandSyntaxLanguage": "语言", + "commandSyntaxLarge": "大", + "commandSyntaxLeader": "领导", + "commandSyntaxList": "列表", + "commandSyntaxMarker": "标记", + "commandSyntaxMarkers": "标记", + "commandSyntaxMarket": "市场", + "commandSyntaxMetal": "金属", + "commandSyntaxMute": "静音", + "commandSyntaxNote": "备注", + "commandSyntaxNotes": "备注", + "commandSyntaxOff": "关闭", + "commandSyntaxOffline": "离线", + "commandSyntaxOn": "开启", + "commandSyntaxOnline": "在线", + "commandSyntaxPlayer": "玩家", + "commandSyntaxPlayers": "玩家", + "commandSyntaxPop": "人口", + "commandSyntaxProx": "邻近", + "commandSyntaxRecycle": "回收", + "commandSyntaxRemove": "移除", + "commandSyntaxResearch": "研究", + "commandSyntaxSearch": "搜索", + "commandSyntaxSend": "发送", + "commandSyntaxSmall": "小", + "commandSyntaxStack": "堆叠", + "commandSyntaxStatus": "状态", + "commandSyntaxSteamid": "SteamID", + "commandSyntaxStone": "石头", + "commandSyntaxSubscribe": "订阅", + "commandSyntaxTTS": "文本转语音", + "commandSyntaxTeam": "团队", + "commandSyntaxTime": "时间", + "commandSyntaxTimer": "计时器", + "commandSyntaxTimers": "计时器", + "commandSyntaxTranslateFromTo": "翻译从...到...", + "commandSyntaxTranslateTo": "翻译至", + "commandSyntaxTravelingVendor": "供应商", + "commandSyntaxTwig": "枝条", + "commandSyntaxUnmute": "取消静音", + "commandSyntaxUnsubscribe": "取消订阅", + "commandSyntaxUpkeep": "维护", + "commandSyntaxUptime": "正常运行时间", + "commandSyntaxWipe": "擦除", + "commandSyntaxWood": "木头", + "commandsAlarmDesc": "智能警报操作。", + "commandsAlarmEditDesc": "编辑智能警报的属性。", + "commandsAlarmEditIdDesc": "智能警报的 ID。", + "commandsAlarmEditImageDesc": "设置最能代表智能警报的图像。", + "commandsAliasAddAliasDesc": "要使用的别名。", + "commandsAliasAddDesc": "添加别名。", + "commandsAliasAddValueDesc": "命令/字符序列。", + "commandsAliasDesc": "为命令/字符序列创建别名。", + "commandsAliasRemoveDesc": "删除别名。", + "commandsAliasRemoveIndexDesc": "要删除的别名的索引。", + "commandsAliasShowDesc": "显示所有注册的别名。", + "commandsBlacklistAddDesc": "将用户添加到黑名单。", + "commandsBlacklistDesc": "将用户列入机器人的黑名单。", + "commandsBlacklistDiscordUserDesc": "Discord 用户。", + "commandsBlacklistRemoveDesc": "从黑名单中删除用户。", + "commandsBlacklistShowDesc": "显示黑名单用户。", + "commandsBlacklistSteamidDesc": "用户的 SteamID。", + "commandsCctvDesc": "显示纪念碑的 CCTV 代码", + "commandsCraftDesc": "显示制作物品的成本。", + "commandsCraftQuantityDesc": "制作物品的数量。", + "commandsCredentialsAddDesc": "添加 FCM 凭证。", + "commandsCredentialsDesc": "设置/清除用户账户的 FCM 凭证。", + "commandsCredentialsRemoveDesc": "移除 FCM 凭证。", + "commandsCredentialsRemoveSteamIdDesc": "要移除的 FCM 凭证的 SteamID。", + "commandsCredentialsSetHosterDesc": "设置 FCM 凭证的主机。", + "commandsCredentialsSetHosterSteamIdDesc": "FCM 凭证主机的 SteamID。", + "commandsCredentialsShowDesc": "显示当前注册的 FCM 凭证。", + "commandsDecayDesc": "显示物品的衰变时间。", + "commandsDespawnDesc": "显示物品的消失时间。", + "commandsHelpCommandList": "命令列表", + "commandsHelpDesc": "显示帮助信息。", + "commandsHelpHowToCredentials": "如何注册凭证", + "commandsHelpHowToPairServer": "如何将机器人与 Rust 服务器配对", + "commandsItemDesc": "获取物品的详细信息。", + "commandsLeaderDesc": "从/给团队成员领导权。", + "commandsLeaderMemberDesc": "团队成员的名称。", + "commandsMapAllDesc": "获取包括纪念碑名称和标记的地图。", + "commandsMapCleanDesc": "获取干净的地图。", + "commandsMapDesc": "获取当前连接的服务器地图图像。", + "commandsMapMarkersDesc": "获取包含标记的地图。", + "commandsMapMonumentsDesc": "获取包含纪念碑名称的地图。", + "commandsMarketDesc": "游戏内自动售货机的操作。", + "commandsMarketListDesc": "显示订阅列表。", + "commandsMarketOrderDesc": "订单类型。", + "commandsMarketSearchDesc": "在自动售货机中搜索物品。", + "commandsMarketSubscribeDesc": "在自动售货机中订阅物品。", + "commandsMarketUnsubscribeDesc": "取消自动售货机中的物品订阅。", + "commandsPlayersBattlemetricsIdDesc": "服务器的 Battlemetrics ID(默认:已连接的服务器)。", + "commandsPlayersDesc": "根据 Battlemetrics 获取玩家/玩家信息。", + "commandsPlayersNameDesc": "根据玩家姓名在 Battlemetrics 上搜索玩家。", + "commandsPlayersPlayerIdDesc": "根据玩家 ID 在 Battlemetrics 上搜索玩家。", + "commandsPlayersPlayerIdPlayerIdDesc": "玩家的玩家 ID。", + "commandsPlayersStatusDesc": "搜索在线/离线/任何状态的玩家。", + "commandsRecycleRecyclerTypeDesc": "回收机类型(回收机、粉碎机、安全区回收机)。", + "commandsRecycleDesc": "显示回收物品的输出。", + "commandsRecycleQuantityDesc": "回收物品的数量。", + "commandsResearchDesc": "显示研究物品的成本。", + "commandsResetAlarmsDesc": "重置警报频道。", + "commandsResetDesc": "重置 Discord 频道。", + "commandsResetInformationDesc": "重置信息频道。", + "commandsResetServersDesc": "重置服务器频道。", + "commandsResetSettingsDesc": "重置设置频道。", + "commandsResetStorageMonitorsDesc": "重置存储监控频道。", + "commandsResetSwitchesDesc": "重置开关和开关组频道。", + "commandsResetTrackersDesc": "重置追踪器频道。", + "commandsRoleClearDesc": "清除角色(允许所有人查看 rustplusplus 频道)。", + "commandsRoleDesc": "设置/清除将能够查看 rustplusplus 类别内容的特定角色。", + "commandsRoleSetDesc": "设置角色。", + "commandsRoleSetRoleDesc": "rustplusplus 频道将对其可见的角色。", + "commandsStackDesc": "显示物品的堆叠大小。", + "commandsStoragemonitorDesc": "存储监控操作。", + "commandsStoragemonitorEditDesc": "编辑存储监控的属性。", + "commandsStoragemonitorEditIdDesc": "存储监控的 ID。", + "commandsStoragemonitorEditImageDesc": "设置最能代表存储监控的图像。", + "commandsSwitchDesc": "智能开关操作。", + "commandsSwitchEditDesc": "编辑智能开关的属性。", + "commandsSwitchEditIdDesc": "智能开关的 ID。", + "commandsSwitchEditImageDesc": "设置最能代表智能开关的图像。", + "commandsUpkeepDesc": "显示物品的维护成本。", + "commandsUptimeBotDesc": "显示机器人的正常运行时间。", + "commandsUptimeDesc": "显示机器人和服务器的正常运行时间。", + "commandsUptimeServerDesc": "显示服务器的正常运行时间。", + "commandsVoiceBotJoinedVoice": "机器人已加入语音频道", + "commandsVoiceBotLeftVoice": "机器人已离开语音频道", + "commandsVoiceDesc": "机器人语音命令", + "commandsVoiceFemale": "女性", + "commandsVoiceFemaleDescription": "设置语音演员性别为女性", + "commandsVoiceGenderDesc": "设置机器人的语音演员性别。", + "commandsVoiceJoin": "加入名为 {name} 的语音频道,ID 为 {id},位于公会 {guild}", + "commandsVoiceJoinDesc": "加入语音频道", + "commandsVoiceLeave": "离开名为 {name} 的语音频道,ID 为 {id},位于公会 {guild}", + "commandsVoiceLeaveDesc": "离开语音频道", + "commandsVoiceMale": "男性", + "commandsVoiceMaleDescription": "设置语音演员性别为男性", + "commandsVoiceNotInVoice": "你不在语音频道中", + "connect": "连接", + "connectCap": "连接", + "connected": "已连接", + "connectedCap": "已连接", + "connectedToServer": "已连接到服务器。", + "connectingCap": "正在连接", + "connectingToServer": "正在连接到服务器...", + "connectionEvents": "连接事件", + "connectionRefusedTo": "拒绝连接至:{id}。", + "connectionsCap": "连接", + "couldNotAddStepTracers": "无法添加步骤追踪器。", + "couldNotAppendMapMarkers": "无法添加地图标记,rustplus 信息实例未设置。", + "couldNotAppendMapMonuments": "无法添加地图纪念碑,rustplus 信息实例未设置。", + "couldNotAppendMapTracers": "无法添加地图追踪器,rustplus 信息实例未设置。", + "couldNotConnectTo": "无法连接至:{id}。", + "couldNotCreateCategory": "无法创建类别:{name}", + "couldNotCreateTextChannel": "无法创建文本频道:{name}", + "couldNotDeferInteraction": "无法推迟互动。", + "couldNotDeleteCategory": "无法删除类别:{categoryId}", + "couldNotDeleteChannel": "无法删除频道:{channelId}", + "couldNotDeleteMessage": "无法删除消息:{message}", + "couldNotFindAnyPlayers": "找不到任何玩家。", + "couldNotFindCategory": "找不到类别:{category}", + "couldNotFindChannel": "找不到频道:{channel}", + "couldNotFindCraftDetails": "找不到 {name} 的制作详情。", + "couldNotFindDecayDetails": "找不到 {name} 的衰变详情。", + "couldNotFindDespawnDetails": "找不到 {name} 的消失详情。", + "couldNotFindGuild": "找不到公会:{guildId}", + "couldNotFindLanguage": "找不到语言:{language}", + "couldNotFindMessage": "找不到消息 {message}", + "couldNotFindPlayer": "找不到玩家 {name}。", + "couldNotFindPlayerId": "找不到带有 id {id} 的玩家。", + "couldNotFindRecycleDetails": "找不到 {name} 的回收详情。", + "couldNotFindResearchDetails": "找不到 {name} 的研究详情。", + "couldNotFindRole": "找不到角色:{roleId}", + "couldNotFindStackDetails": "找不到 {name} 的堆叠详情。", + "couldNotFindTeammate": "找不到队友:{name}。", + "couldNotFindUpkeepDetails": "找不到 {name} 的维护详情。", + "couldNotFindUser": "找不到用户:{userId}", + "couldNotGetChannelWithId": "无法获取带有 id:{id} 的频道。", + "couldNotIdentifyMember": "无法识别团队成员:{name}。", + "couldNotPerformBulkDelete": "无法在频道:{channel} 上执行批量删除。", + "couldNotPerformMessageDelete": "无法执行消息删除。", + "couldNotPerformMessagesFetch": "无法在频道:{channel} 上执行消息提取。", + "couldNotRegisterSlashCommands": "无法为公会:{guildId} 注册斜杠命令。", + "couldNotSetParent": "无法为频道:{channelId} 设置父级。", + "craft": "制作", + "crate": "箱子", + "createGroupCap": "创建组", + "createTrackerCap": "创建追踪器", + "credentialsAddedSuccessfully": "FCM 凭证已成功添加给 steamId:{steamId}!", + "credentialsAlreadyRegistered": "FCM 凭证已为 steamId:{steamId} 注册!", + "credentialsCannotStartLiteAlreadyHoster": "无法为 steamId:{steamId} 启动 FCM 监听器 Lite。已经是主机。", + "credentialsDoNotExist": "FCM 凭证不存在于 steamId:{steamId}。", + "credentialsHosterNotSetForGuild": "公会 {id} 的 FCM 凭证主机未设置,请设置主机。", + "credentialsNotRegistered": "FCM 凭证未为 steamId:{steamId} 注册!", + "credentialsNotRegisteredForGuild": "公会:{id} 未注册 FCM 凭证,无法启动 FCM 监听器。", + "credentialsRemovedSuccessfully": "FCM 凭证已成功移除 steamId:{steamId}!", + "credentialsSetHosterSuccessfully": "FCM 凭证主机已成功设置为 steamId:{steamId}。", + "currencySign": "货币符号", + "currentCommandDelay": "当前命令延迟:{delay} 秒。", + "currentItemHp": "物品的当前 HP。", + "currentPrefixPlaceholder": "当前前缀:{prefix}", + "customCommand": "自定义命令", + "customTimerEditCargoShipEgressLabel": "货船出口时间(秒):", + "customTimerEditCrateOilRigUnlockLabel": "石油钻井平台锁定箱解锁时间(秒):", + "customTimerEditDesc": "编辑自定义计时器", + "customTimersCap": "自定义计时器", + "dash": "破折号", + "dayOfWipe": "擦拭日 {day}", + "deathCap": "死亡", + "decay": "衰变", + "decayTimeForItem": "物品 {item} 的衰变时间为 {time}。", + "decayingCap": "衰变中", + "deleteUnreachableDevicesCap": "删除无法访问的设备", + "despawnTime": "消失时间", + "despawnTimeOfItem": "物品 {item} 的消失时间为 {time}。", + "deviceIsAlreadyOnOff": "{device} 已经是 {status} 状态。", + "deviceIsCurrentlyOnOff": "{device} 当前是 {status} 状态。", + "deviceWasTurnedOnOff": "{device} 被转换为 {status} 状态。", + "disabledCap": "已禁用", + "discoFloor": "迪斯科舞池", + "disconnectCap": "断开连接", + "disconnected": "已断开连接", + "disconnectedCap": "已断开连接", + "disconnectedFromServer": "已从服务器断开连接。", + "discordCap": "Discord", + "discordUsers": "Discord 用户", + "displayInformationBattlemetricsAllOnlinePlayers": "应该在信息频道显示来自 Battlemetrics 的所有在线玩家吗?", + "displayingMap": "正在显示 {mapName} 地图。", + "displayingOnlinePlayers": "正在显示在线玩家。", + "distanceDirectionGrid": "{distance}米,方向 {direction}° [{grid}]。", + "doorController": "门控制器", + "dot": "点", + "eastOfGrid": "网格东侧", + "editCap": "编辑", + "editing": "正在编辑", + "editingOf": "正在编辑 {entity}", + "egressInTime": "在 {time} 时离开 {location}。", + "eight": "八", + "elevator": "电梯", + "empty": "空的", + "enabledCap": "已启用", + "entityId": "实体 ID", + "equalsSign": "等号", + "errorCap": "错误", + "errorExecutingCommand": "执行此命令时出现错误!", + "eventCap": "事件", + "eventInfo": "事件信息", + "exclamationMark": "感叹号", + "failedToScrapeProfileName": "无法抓取个人资料名称:{link}。", + "failedToScrapeProfilePicture": "无法抓取个人资料图片:{link}。", + "fcmCredentials": "FCM 凭证", + "fcmListenerStartHost": "公会ID为 {guildId},steamId 为 {steamId} 的 FCM 监听器主机将在 5 秒后启动。", + "fcmListenerStartLite": "公会ID为 {guildId},steamId 为 {steamId} 的 FCM 监听器 Lite 将在 5 秒后启动。", + "ferryTerminal": "渡轮码头", + "fishingVillage": "渔村", + "five": "五", + "four": "四", + "giantExcavatorPit": "巨型挖掘机坑", + "greaterThanSign": "大于符号", + "groupAddSwitchDesc": "将开关添加至 {group}", + "groupRemoveSwitchDesc": "从 {group} 移除开关", + "harbor": "港口", + "hasBeenAliveLongest": "{name} 存活时间最长 ({time})。", + "hash": "井号", + "hbhfSensor": "HBHF 传感器", + "heart": "心", + "heater": "加热器", + "heavyScientistCalledSetting": "当重型科学家被召唤至石油钻井平台时发送通知。", + "heavyScientistsCalledLarge": "重型科学家被召唤至大型石油钻井平台 {location}。", + "heavyScientistsCalledSmall": "重型科学家被召唤至小型石油钻井平台 {location}。", + "hideTrademark": "隐藏商标。", + "hoster": "主机", + "hp": "生命值", + "hpExceedMax": "生命值 {hp} 超过最大值 {max}。", + "hqmQuarry": "高质量金属采石场", + "ignoreSetAvatar": "忽略设置头像", + "ignoreSetNickname": "忽略设置昵称", + "ignoreSetUsername": "忽略设置用户名", + "inGameBotMessagesMuted": "游戏内机器人消息已静音。", + "inGameBotMessagesUnmuted": "游戏内机器人消息已取消静音。", + "inGameCap": "游戏内", + "inGameEventInfo": "游戏内事件信息", + "inGameTeamNotificationsSetting": "游戏内团队通知。", + "inGameTime": "游戏内时间:{time}。", + "index": "索引", + "infoCap": "信息", + "inside": "内部", + "interactionEditReplyFailed": "交互编辑回复失败:{error}", + "interactionInvalidChannel": "来自无效频道的交互。", + "interactionReplyFailed": "交互回复失败:{error}", + "interactionUpdateFailed": "交互更新失败:{error}", + "invalidBattlemetricsId": "无效的 Battlemetrics ID。", + "invalidGuildOrChannel": "无效的公会或频道。", + "invalidHpInterval": "无效的 HP 区间 {hp}。", + "invalidId": "无效的 ID:{id}。", + "invalidStructureType": "无效的结构类型 {type}。", + "invalidSubcommand": "无效的子命令。", + "invalidTimeDistance": "无效的时间距离:{distance},之前:{prevTime},现在:{newTime}", + "isDecaying": "{device} 正在衰变!", + "isNoLongerConnected": "{device} 不再电连接!", + "item": "物品", + "itemAvailableInVendingMachine": "{items} 刚在 [{location}] 的自动售货机中上架。", + "itemAvailableNotifyInGameSetting": "订阅列表中的物品在自动售货机中上架时,是否通知游戏内?", + "junkyard": "废品场", + "justSubscribedToItem": "刚订阅物品 {name}。", + "languageCode": "语言代码:{code}", + "languageLangNotSupported": "{language} 语言不受支持。", + "languageNotSupported": "该语言不受支持。", + "largeBarn": "大型谷仓", + "largeFishingVillage": "大型渔村", + "largeOilRig": "大型石油钻井平台", + "largeWoodBox": "大木箱", + "lastTrigger": "最后触发", + "launchSite": "发射场", + "leaderAlreadyLeader": "{name} 已是团队领袖。", + "leaderCommandIsDisabled": "领导命令在设置中已禁用。", + "leaderCommandOnlyWorks": "领导命令只在当前领导是 {name} 时生效。", + "leaderTransferred": "团队领导权已转移给 {name}。", + "leavingMapAt": "在 {location} 离开。", + "lessThanSign": "小于符号", + "lighthouse": "灯塔", + "linkCap": "链接", + "location": "位置", + "lockedCrateLargeOilRigUnlocked": "在 {location} 的大型石油钻井平台上的锁定箱已解锁。", + "lockedCrateOilRigUnlockedSetting": "当石油钻井平台上的锁定箱解锁时发送通知。", + "lockedCrateSmallOilRigUnlocked": "在 {location} 的小型石油钻井平台上的锁定箱已解锁。", + "logDiscordCommand": "Discord 命令 - 公会:{guild},频道:{channel},用户:{user},消息:{message}。", + "logDiscordMessage": "Discord 消息 - 公会:{guild},频道:{channel},用户:{user},消息:{message}。", + "logInGameCommand": "{type} - 命令:{command},用户:{user}。", + "logInGameMessage": "消息:{message},用户:{user}", + "logSmartSwitchGroupValueChange": "智能开关组 - 值:{value}。", + "logSmartSwitchValueChange": "智能开关 - 值:{value}。", + "loggedInAs": "登录为:{name}", + "makeSureApplicationsCommandsEnabled": "确保在创建邀请 URL 时选中 applications.commands。", + "map": "地图", + "mapSalt": "地图盐", + "mapSeed": "地图种子", + "mapSize": "地图大小", + "mapWipeDetectedNotifySetting": "检测到地图擦拭时,应通知 {group} 吗?", + "markerAdded": "在 [{location}] 添加的标记 {name}。", + "markerDoesNotExist": "标记 {name} 不存在。", + "markerLocation": "标记 {name} 在 [{location}],距离 {player} {distance}米,方向 {direction}°。", + "markerRemoved": "在 [{location}] 移除的标记 {name}。", + "message": "消息", + "messageCap": "消息", + "messageDeletedIn30": "此消息将在 30 秒后删除。", + "messageEditFailed": "消息编辑失败:{error}", + "messageReplyFailed": "消息回复失败:{error}", + "messageSendFailed": "消息发送失败:{error}", + "messageWasSent": "消息已发送。", + "militaryTunnel": "军事隧道", + "miningOutpost": "采矿哨站", + "missileSilo": "导弹发射井", + "missingArguments": "缺少参数。", + "missingPermission": "你没有权限执行此操作。", + "missingTimerMessage": "缺少计时器消息。", + "modalValueChange": "模态交互 - 验证 ID:{id},值:{value}。", + "more": "更多", + "morePlayers": "{players} ...{number} 更多。", + "mutedCap": "已静音", + "name": "名称", + "nameChangeHistory": "名称变更历史", + "new": "新的", + "newVendingMachine": "位于 {location} 的新自动售货机。", + "newsCap": "新闻", + "noActiveTimers": "没有活动计时器。", + "noCommandDelay": "没有命令延迟。", + "noCommunicationSmartSwitch": "无法与智能开关 {name} 通信", + "noData": "无数据。", + "noDataOnLargeOilRig": "大型石油钻井平台当前无数据。", + "noDataOnSmallOilRig": "小型石油钻井平台当前无数据。", + "noDelayCap": "无延迟", + "noItemFound": "在任何自动售货机中都找不到物品...", + "noItemWithIdFound": "找不到带有 id {id} 的物品。", + "noItemWithNameFound": "找不到名为 {name} 的物品。", + "noNameIdGiven": "未给出 '名称' 或 'ID'。", + "noOneIsAfk": "没有人暂离。", + "noOneIsOffline": "没有人离线。", + "noOneIsOnline": "没有人在线。", + "noRegisteredConnectionEvents": "尚未注册连接事件。", + "noRegisteredConnectionEventsUser": "尚未为 {user} 注册连接事件。", + "noRegisteredDeathEvents": "尚未注册死亡事件。", + "noRegisteredDeathEventsUser": "尚未为 {user} 注册死亡事件。", + "noRegisteredEvents": "尚未注册事件。", + "noRegisteredMarkers": "没有注册的标记。", + "noSavedNotes": "没有保存的备注。", + "noToolCupboardWereFound": "未找到工具柜监控。", + "none": "无", + "northEast": "东北", + "northOfGrid": "网格北侧", + "northWest": "西北", + "notAValidOrderType": "{order} 不是有效的订单类型。", + "notActive": "未激活。", + "notConnectedToRustServer": "当前未连接至 rust 服务器。", + "notExistInSubscription": "物品 {name} 不在订阅列表中。", + "notFoundCap": "未找到", + "notPartOfRole": "你不是 {role} 角色的一部分,因此你不能运行机器人命令。", + "notShowingCap": "不显示", + "noteCap": "备注", + "noteIdDoesNotExist": "备注 ID:{id} 不存在。", + "noteIdInvalid": "备注 ID 无效。", + "noteIdWasRemoved": "备注 ID:{id} 已移除。", + "noteSaved": "备注已保存。", + "offCap": "关闭", + "offline": "离线", + "offlineTime": "离线时间", + "oilRig": "石油钻井平台", + "old": "旧的", + "onCap": "开启", + "one": "一", + "online": "在线", + "onlineTime": "在线时间", + "onlyOneInTeam": "你是团队中唯一的成员。", + "outpost": "哨所", + "outside": "外部", + "oxumsGasStation": "欧克萨姆加油站", + "pairing": "配对", + "patrolHelicopter": "巡逻直升机", + "patrolHelicopterDestroyedSetting": "当巡逻直升机被摧毁时发送通知。", + "patrolHelicopterDetectedSetting": "检测到巡逻直升机时发送通知。", + "patrolHelicopterEntersMap": "巡逻直升机从 {location} 进入地图。", + "patrolHelicopterLeftMap": "巡逻直升机刚刚在 {location} 离开地图。", + "patrolHelicopterLeftSetting": "巡逻直升机离开地图时发送通知。", + "patrolHelicopterLocatedAt": "巡逻直升机位于 {location}。", + "patrolHelicopterNotCurrentlyOnMap": "巡逻直升机当前不在地图上。", + "patrolHelicopterTakenDown": "巡逻直升机在 {location} 被击落。", + "percentSign": "百分号", + "pipe": "管道", + "playerHasBeenAliveFor": "{name} 已存活 {time}。", + "playerId": "玩家 ID", + "playerJoinedTheTeam": "{name} 加入了团队。", + "playerJustConnected": "{name} 刚刚连接。", + "playerJustConnectedTo": "{name} 刚刚连接到 {server}。", + "playerJustConnectedTracker": "{name} 刚刚通过追踪器 {tracker} 连接。", + "playerJustDied": "{name} 刚刚在 {location} 死亡。", + "playerJustDisconnected": "{name} 刚刚断开连接。", + "playerJustDisconnectedFrom": "{name} 刚刚从 {server} 断开连接。", + "playerJustDisconnectedTracker": "{name} 刚刚从追踪器 {tracker} 断开连接。", + "playerJustReturned": "{name} 刚刚返回({time})。", + "playerJustWentAfk": "{name} 刚刚暂离。", + "playerLeftTheTeam": "{name} 离开了团队。", + "playerNotPairedWithServer": "领导命令无法使用,因为 {name} 未与服务器配对。", + "players": "玩家", + "playersSearch": "玩家搜索", + "plusSign": "加号", + "populationPlayers": "人口:({current}/{max})玩家。", + "populationQueue": "{number} 玩家排队。", + "powerPlant": "发电厂", + "profile": "个人资料", + "proxLocation": "{name} 位于 {caller} {distance}米的方向 {direction}° [{location}]", + "quantity": "数量", + "questionMark": "问号", + "ranch": "牧场", + "ratelimited": "速率限制", + "reconnectingCap": "重新连接", + "reconnectingToServer": "正在重新连接到服务器...", + "recycle": "回收", + "recycler": "回收机", + "recycleCap": "回收", + "remain": "剩余", + "removePlayerCap": "移除玩家", + "removeSwitchCap": "移除开关", + "removedSubscribeItem": "已从订阅中移除物品 {name}。", + "research": "研究", + "researchTable": "研究表", + "resetSuccess": "成功重置 Discord。", + "responseContainError": "响应包含错误属性,值为:{error}。", + "responseIsEmpty": "响应为空。", + "responseIsUndefined": "响应未定义。", + "responseTimeout": "等待响应时达到超时。", + "resultRecycling": "回收结果", + "roleCleared": "rustplusplus 角色已清除。", + "roleSet": "rustplusplus 角色已设置为 {name}。", + "rustMonument": "Rust 纪念碑", + "rustplusOperational": "RUSTPLUS 运行中。", + "safe-zone-recycler": "安全区回收机", + "samsite": "地对空导弹站", + "satelliteDish": "卫星天线", + "scrap": "废料", + "searchResult": "物品搜索结果:**{name}**", + "second": "{second} 秒", + "secondCommandDelay": "{second} 秒命令延迟。", + "seconds": "{seconds} 秒", + "secondsCommandDelay": "{seconds} 秒命令延迟。", + "selectInGamePrefixSetting": "选择应使用的游戏内命令前缀:", + "selectLanguageExtendSetting": "确保运行 **/reset discord** 以成功加载新语言。", + "selectLanguageSetting": "选择机器人使用的语言:", + "selectMenuValueChange": "选择菜单交互 - 验证 ID:{id},值:{value}。", + "selectTrademarkSetting": "选择应在每条游戏内消息中显示的商标。", + "sell": "出售", + "semicolon": "分号", + "sentTextToSpeech": "已发送文本到语音。", + "server": "服务器", + "serverId": "服务器 ID", + "serverInfo": "服务器信息", + "serverInvalid": "与服务器的连接似乎无效。尝试重新配对服务器。", + "serverJustOffline": "服务器刚刚离线。", + "serverJustOnline": "服务器刚刚在线。", + "serverStatus": "服务器状态", + "serviceUnavailable": "服务不可用:{error}", + "setBotLanguage": "将机器人语言设置为:{language}。", + "seven": "七", + "sewerBranch": "下水道支路", + "shouldBotBeMutedSetting": "机器人是否应在游戏内静音?", + "shouldCommandsEnabledSetting": "是否应启用游戏内命令?", + "shouldLeaderCommandEnabledSetting": "是否应启用领导命令?", + "shouldLeaderCommandOnlyForPairedSetting": "领导命令是否仅对与服务器配对的人有效?", + "shouldSmartAlarmNotifyNotConnectedSetting": "即使未在连接的 Rust 服务器上设置,智能警报是否也应通知?", + "shouldSmartAlarmsNotifyInGameSetting": "智能警报是否应在游戏内通知?", + "shouldSmartSwitchNotifyInGameWhenChangedFromDiscord": "当从 Discord 更改智能开关和智能开关组时,是否应在游戏内通知?", + "showingBlacklist": "显示黑名单。", + "showingSubscriptionList": "显示订阅列表。", + "shredder": "礤床儿", + "sirenLight": "警报灯", + "six": "六", + "slash": "斜杠", + "slashCommandInteraction": "斜杠命令交互 - 公会:{guild},频道:{channel},用户:{user},命令:{command},验证 ID:{id}。", + "slashCommandValueChange": "斜杠命令交互 - 验证 ID:{id},值:{value}。", + "slashCommandsSuccessRegister": "成功为公会:{guildId} 注册应用命令。", + "slots": "插槽", + "smallOilRig": "小型石油钻井平台", + "smartAlarm": "智能警报", + "smartAlarmEditSuccess": "成功编辑智能警报 {name}。", + "smartAlarmNotifyExtendSetting": "- 这些警报通知将使用游戏内给定的智能警报的标题和消息。\n- 这些智能警报可能在 discord 的警报文本频道中不可用。", + "smartDeviceNotFound": "{device} 未找到!要么已被摧毁,要么 {user} 已失去工具柜访问权限。", + "smartSwitch": "智能开关", + "smartSwitchAutoDay": "智能开关仅在白天激活。", + "smartSwitchAutoNight": "智能开关仅在夜晚激活。", + "smartSwitchAutoOff": "智能开关将在更新周期期间自动变为非激活状态。", + "smartSwitchAutoOffAnyOnline": "如果任何队友在线,智能开关将自动变为非激活状态。", + "smartSwitchAutoOffProximity": "如果队友在邻近范围内,智能开关将自动变为非激活状态。", + "smartSwitchAutoOn": "智能开关将在更新周期期间自动激活。", + "smartSwitchAutoOnAnyOnline": "如果任何队友在线,智能开关将自动激活。", + "smartSwitchAutoOnProximity": "如果队友在邻近范围内,智能开关将自动激活。", + "smartSwitchEditProximityLabel": "邻近设置(米):", + "smartSwitchEditSuccess": "成功编辑智能开关 {name}。", + "smartSwitchNormal": "智能开关正常工作。", + "smilyFace": "笑脸", + "somethingWrongWithConnection": "连接出了问题。", + "southEast": "东南", + "southOfGrid": "网格南侧", + "southWest": "西南", + "sprinkler": "洒水器", + "stackSize": "堆叠大小", + "stackSizeOfItem": "物品 {item} 的堆叠大小为 {quantity}x。", + "status": "状态", + "statusNotConnectedToServer": "**状态** `未连接到服务器!`", + "statusNotElectronicallyConnected": "**状态** `未电连接!`", + "statusNotFound": "**状态**:未找到", + "steamId": "SteamID", + "stoneQuarry": "石料采石场", + "storageMonitor": "存储监控", + "storageMonitorEditSuccess": "成功编辑存储监控 {name}。", + "streamerMode": "主播模式", + "subscribeToChangesBattlemetrics": "订阅 Battlemetrics 上的不同更改。", + "subscriptionList": "订阅列表", + "subscriptionListEmpty": "物品订阅列表为空。", + "sulfurQuarry": "硫磺采石场", + "switches": "开关", + "teamMember": "团队成员", + "teamMemberInfo": "团队成员信息", + "theDome": "穹顶", + "theIdOfTheItem": "物品的 ID。", + "theNameOfTheItem": "物品的名称。", + "theNameOfThePlayer": "玩家的名称。", + "three": "三", + "tilde": "波浪号", + "time": "时间", + "timeBeforeCargoEntersEgress": "在 {location} 的货船进入出口阶段前 {time}。", + "timeBeforeCrateAtLargeOilRigUnlocks": "在大型石油钻井平台 ({location}) 上的锁定箱解锁前 {time}。", + "timeBeforeCrateAtSmallOilRigUnlocks": "在小型石油钻井平台 ({location}) 上的锁定箱解锁前 {time}。", + "timeCap": "时间", + "timeFormatInvalid": "时间格式无效。", + "timeLeftTimer": "{id}:剩余时间:{time},消息:{message}", + "timeSinceAlarmWasTriggered": "警报 {alarm} 触发后过去了 {time}。", + "timeSinceCargoLeft": "自货船离开地图后过去了 {time}。", + "timeSinceChinook47OnMap": "自上次支奴干 47 在地图上出现后过去了 {time}。", + "timeSinceHeavyScientistsOnLarge": "自重型科学家上次被召唤至大型石油钻井平台后过去了 {time}。", + "timeSinceHeavyScientistsOnSmall": "自重型科学家上次被召唤至小型石油钻井平台后过去了 {time}。", + "timeSinceLast": "自上次以来过去了 {time}。", + "timeSinceLastEvent": "自上次事件以来过去了 {time}。", + "timeSinceLastSinceDestroyedLong": "自上次巡逻直升机在地图上出现以来过去了 {time1},自它上次被击落以来过去了 {time2}{location}。", + "timeSinceLastSinceDestroyedShort": "自上次以来过去了 {time1}。\n自摧毁以来过去了 {time2}{location}。", + "timeSincePatrolHelicopterWasOnMap": "自巡逻直升机上次在地图上出现以来过去了 {time}。", + "timeSinceTravelingVendorWasOnMap": "{time} 已经过去,自流动商人上次出现在地图上。", + "timeSinceWipe": "自擦拭以来过去了 {time}。", + "timeTill": "距离 {event} 的时间", + "timeTillDaylight": "距离白天还有 {time}。", + "timeTillNightfall": "距离夜晚还有 {time}。", + "timeTillStructureDecay": "距离 {type} 墙壁衰变还有 {time}。", + "timeUntilUnlocksAt": "在 {location} 解锁前还有 {time}。", + "timer": "计时器:{message}。", + "timerIdDoesNotExist": "计时器 ID:{id} 不存在。", + "timerIdInvalid": "计时器 ID 无效。", + "timerRemoved": "计时器 ID:{id} 已移除。", + "timerSet": "已为 {time} 设置计时器。", + "tokensDidNotReplenish": "令牌未及时补充。", + "toolCupboard": "工具柜", + "total": "总计", + "tracker": "追踪器", + "trackerAddPlayerDesc": "将玩家添加至 {tracker}", + "trackerRemovePlayerDesc": "从 {tracker} 移除玩家", + "trademarkShownBeforeMessage": "每条游戏内消息前将显示 {trademark}。", + "trainYard": "火车站", + "travelingVendor": "流动商人", + "travelingVendorDetectedSetting": "检测到流动商人时,发送通知。", + "travelingVendorHaltedAt": "流动商人停在 {location}。", + "travelingVendorHaltedSetting": "当流动商人停止移动时,发送通知。", + "travelingVendorLeftSetting": "当流动商人离开地图时,发送通知。", + "travelingVendorLocatedAt": "流动商人位于 {location}。", + "travelingVendorLeftMap": "流动商人刚刚在 {location} 离开了地图。", + "travelingVendorNotCurrentlyOnMap": "流动商人当前不在地图上。", + "travelingVendorResumedAt": "流动商人在 {location} 重新开始移动。", + "travelingVendorSpawnedAt": "流动商人出现在 {location}。", + "turnOffCap": "关闭", + "turnOnCap": "开启", + "turningGroupOnOff": "将组 {group} 转换为 {status}。", + "two": "二", + "type": "类型", + "unavailable": "不可用", + "underscore": "下划线", + "underwater": "水下", + "underwaterLab": "水下实验室", + "unhandledRejection": "未处理的拒绝:{error}", + "unknown": "未知", + "unknownInteraction": "未知交互...", + "unmutedCap": "未静音", + "updateCap": "更新", + "upkeep": "维护", + "upkeepForItem": "物品 {item} 的维护费用为 {cost}。", + "userAddedToBlacklist": "{user} 已被添加至黑名单。", + "userAlreadyInBlacklist": "{user} 已在黑名单中。", + "userButtonInteraction": "按钮交互 - 公会:{guild},频道:{channel},用户:{user},自定义 ID:{customid},验证 ID:{id}。", + "userButtonInteractionSuccess": "按钮交互 - 验证 ID:{id} 成功", + "userJustConnected": "{name} 刚刚连接。", + "userModalInteraction": "模态交互 - 公会:{guild},频道:{channel},用户:{user},自定义 ID:{customid},验证 ID:{id}。", + "userModalInteractionSuccess": "模态交互 - 验证 ID:{id} 成功", + "userNotInBlacklist": "{user} 不在黑名单中。", + "userNotRegistered": "{user} 未注册。", + "userPartOfBlacklist": "验证 ID:{id},{user} 是黑名单的一部分。", + "userPartOfBlacklistDiscord": "黑名单用户!公会:{guild},频道:{channel},用户:{user},消息:{message}。", + "userPartOfBlacklistInGame": "黑名单用户!用户:{user},消息:{message}。", + "userRemovedFromBlacklist": "{user} 已从黑名单中移除。", + "userSaid": "{user} 说,{text}", + "userSelectMenuInteraction": "选择菜单交互 - 公会:{guild},频道:{channel},用户:{user},自定义 ID:{customid},验证 ID:{id}。", + "userSelectMenuInteractionSuccess": "选择菜单交互 - 验证 ID:{id} 成功", + "userTurnedOnOffSmartSwitchFromDiscord": "{user} 通过 Discord 将智能开关 {name} 转换为 {status}。", + "userTurnedOnOffSmartSwitchGroupFromDiscord": "{user} 通过 Discord 将智能开关组 {name} 转换为 {status}。", + "value": "值", + "vendingMachine": "自动售货机", + "vendingMachineDetectedSetting": "检测到新自动售货机时发送通知。", + "voiceCap": "语音", + "warningCap": "警告", + "waterTreatmentPlant": "水处理厂", + "websiteCap": "网站", + "websocketClosedBeforeConnection": "WebSocket 在连接建立前已关闭。", + "westOfGrid": "网格西侧", + "wipe": "擦拭", + "wipeDetected": "检测到擦拭!", + "yield": "产量", + "youAreAlreadyLeader": "你已是领导。", + "youAreNotPairedWithServer": "领导命令无法使用,因为你未与服务器配对。" +} diff --git a/src/resources/images/events/traveling_vendor_logo.png b/src/resources/images/events/traveling_vendor_logo.png index 68132296e..f66327566 100644 Binary files a/src/resources/images/events/traveling_vendor_logo.png and b/src/resources/images/events/traveling_vendor_logo.png differ diff --git a/src/resources/images/settings/general_settings_logo_zh.png b/src/resources/images/settings/general_settings_logo_zh.png new file mode 100644 index 000000000..4c58948e3 Binary files /dev/null and b/src/resources/images/settings/general_settings_logo_zh.png differ diff --git a/src/resources/images/settings/notification_settings_logo_zh.png b/src/resources/images/settings/notification_settings_logo_zh.png new file mode 100644 index 000000000..c12bfeac8 Binary files /dev/null and b/src/resources/images/settings/notification_settings_logo_zh.png differ diff --git a/src/staticFiles/actors.json b/src/staticFiles/actors.json index e1e978022..dcef03eed 100644 --- a/src/staticFiles/actors.json +++ b/src/staticFiles/actors.json @@ -42,5 +42,9 @@ "tr":{ "male": "Mehmet", "female": "Miray" + }, + "zh":{ + "male": "cmn-CN-Wavenet-B", + "female": "Zhiyu" } } \ No newline at end of file diff --git a/src/structures/MapMarkers.js b/src/structures/MapMarkers.js index 6709e24ba..c8c25f3dc 100644 --- a/src/structures/MapMarkers.js +++ b/src/structures/MapMarkers.js @@ -251,8 +251,17 @@ class MapMarkers { return remainingMarkersOfType; } - - + isVendingMachineBlacklisted(marker) { + if (marker.type !== this.types.VendingMachine) return false; + + const instance = this.client.getInstance(this.rustplus.guildId); + const marketBlacklist = instance.marketBlacklist; + + return marketBlacklist.some(blacklist => + marker.name.toLowerCase().includes(blacklist.toLowerCase()) + ); + } + /* Update event map markers */ @@ -310,7 +319,7 @@ class MapMarkers { marker.location = pos; - if (!this.rustplus.isFirstPoll) { + if (!this.rustplus.isFirstPoll && !this.isVendingMachineBlacklisted(marker)) { if (!this.knownVendingMachines.some(e => e.x === marker.x && e.y === marker.y)) { this.rustplus.sendEvent( this.rustplus.notificationSettings.vendingMachineDetectedSetting, diff --git a/src/structures/RustLabs.js b/src/structures/RustLabs.js index cf2a2bb6d..7db9ce46f 100644 --- a/src/structures/RustLabs.js +++ b/src/structures/RustLabs.js @@ -469,10 +469,10 @@ class RustLabs { } if (!foundName) { - foundName = this.getClosestBuildingBlockNameByName(name); + foundName = this.items.getClosestItemIdByName(name); if (foundName) { - if (this.durabilityData['buildingBlocks'].hasOwnProperty(foundName)) { - type = 'buildingBlocks'; + if (this.durabilityData['items'].hasOwnProperty(foundName)) { + return this.getDurabilityDetailsById(foundName, group, which, orderedBy); } else { foundName = null; @@ -481,10 +481,10 @@ class RustLabs { } if (!foundName) { - foundName = this.items.getClosestItemIdByName(name); + foundName = this.getClosestBuildingBlockNameByName(name); if (foundName) { - if (this.durabilityData['items'].hasOwnProperty(foundName)) { - return this.getDurabilityDetailsById(foundName, group, which, orderedBy); + if (this.durabilityData['buildingBlocks'].hasOwnProperty(foundName)) { + type = 'buildingBlocks'; } else { foundName = null; @@ -529,7 +529,7 @@ class RustLabs { content = this.getArrayOrderedByChoice(content, orderedBy); - return ['items', id, this.items.items[id], content]; + return ['items', this.items.items[id].name, this.items.items[id], content]; } diff --git a/src/structures/RustPlus.js b/src/structures/RustPlus.js index 39820fa6a..0461d9fe4 100644 --- a/src/structures/RustPlus.js +++ b/src/structures/RustPlus.js @@ -38,6 +38,7 @@ const Map = require('../util/map.js'); const RustPlusLite = require('../structures/RustPlusLite'); const TeamHandler = require('../handlers/teamHandler.js'); const Timer = require('../util/timer.js'); +const Durability = require('../commands/durability.js'); const TOKENS_LIMIT = 24; /* Per player */ const TOKENS_REPLENISH = 3; /* Per second */ @@ -2746,6 +2747,38 @@ class RustPlus extends RustPlusLib { return strings; } + + getCommandRaidCost(command) { + const prefix = this.generalSettings.prefix; + const commandRaid = `${prefix}${Client.client.intlGet(this.guildId, 'commandSyntaxRaid')}`; + const commandRaidEn = `${prefix}${Client.client.intlGet('en', 'commandSyntaxRaid')}`; + if (command.toLowerCase().startsWith(`${commandRaid} `)) { + command = command.slice(`${commandRaid} `.length).trim(); + } + else { + command = command.slice(`${commandRaidEn} `.length).trim(); + } + + const durability = Durability.getDurabilityData(command, null, Client.client, this.guildId); + let raidCosts = `${durability[1]}: `; + + if(!durability) { + return Client.client.intlGet(this.guildId, 'noItemWithNameFound', { + name: command + }); + } + + const sortedItems = Object.values(durability[3].explosive).sort((a, b) => { + const sulfurA = a[0].sulfur === null ? Infinity : Number(a[0].sulfur); + const sulfurB = b[0].sulfur === null ? Infinity : Number(b[0].sulfur); + return sulfurA - sulfurB; + }).slice(0,3); + for (const item of sortedItems) { + raidCosts += `${item[0].itemName} ${item[0].timeString} (${item[0].quantity}) ${item[0].sulfur}, `; + } + + return raidCosts.trim().trim(","); + } } module.exports = RustPlus; diff --git a/src/util/CreateInstanceFile.js b/src/util/CreateInstanceFile.js index 3ad0f1dcc..2f7d071a4 100644 --- a/src/util/CreateInstanceFile.js +++ b/src/util/CreateInstanceFile.js @@ -62,6 +62,7 @@ module.exports = (client, guild) => { buy: [], sell: [] }, + marketBlacklist: [], teamChatColors: {}, blacklist: { discordIds: [], @@ -174,6 +175,7 @@ module.exports = (client, guild) => { buy: [], sell: [] } + if (!instance.hasOwnProperty('marketBlacklist')) instance.marketBlacklist = []; if (!instance.marketSubscriptionList.hasOwnProperty('all')) instance.marketSubscriptionList['all'] = []; if (!instance.marketSubscriptionList.hasOwnProperty('buy')) instance.marketSubscriptionList['buy'] = []; if (!instance.marketSubscriptionList.hasOwnProperty('sell')) instance.marketSubscriptionList['sell'] = [];