mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-24 12:09:51 +02:00
Compare commits
61
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f355cb9f76 | ||
|
|
e42576b005 | ||
|
|
f68198475e | ||
|
|
896ae20dce | ||
|
|
b8fdc5424d | ||
|
|
204c3eacc1 | ||
|
|
4d0f21e10b | ||
|
|
d3202e8607 | ||
|
|
a438eb704f | ||
|
|
1569de4475 | ||
|
|
0f022f8295 | ||
|
|
75c21a5129 | ||
|
|
5092d43e8e | ||
|
|
56d5d5e956 | ||
|
|
70eca3293b | ||
|
|
4f7ee54ef7 | ||
|
|
269df9586d | ||
|
|
3152c18840 | ||
|
|
52630596b8 | ||
|
|
7e184b8be0 | ||
|
|
877ba9408d | ||
|
|
8dc9a6b46d | ||
|
|
b3e439669b | ||
|
|
08c909fbe2 | ||
|
|
a44e2e9866 | ||
|
|
bae2f253bc | ||
|
|
d485a463dd | ||
|
|
3da1ed4d6c | ||
|
|
051e9ec74a | ||
|
|
486171f4db | ||
|
|
72de42a9ab | ||
|
|
404e6625c0 | ||
|
|
32e4bf3fd2 | ||
|
|
0d1088fefb | ||
|
|
1a17d607fb | ||
|
|
dcda627518 | ||
|
|
c130da7f0e | ||
|
|
e2df4d35b8 | ||
|
|
7739dbd0a3 | ||
|
|
9b7aa13d61 | ||
|
|
84ecaec5d3 | ||
|
|
01a5f1bd47 | ||
|
|
de0433ca02 | ||
|
|
cf76ae7136 | ||
|
|
ea21636c4e | ||
|
|
dafa834d28 | ||
|
|
f1a1c78588 | ||
|
|
14d16e5daf | ||
|
|
b52c1fc2d9 | ||
|
|
f45b24f7ab | ||
|
|
6ae175e5e0 | ||
|
|
0df27c38a1 | ||
|
|
e27cc3f6ed | ||
|
|
968c3957d0 | ||
|
|
577d2323a8 | ||
|
|
625c6cc649 | ||
|
|
9bc753b512 | ||
|
|
fb34e6ce2f | ||
|
|
f882ea29e2 | ||
|
|
62f68f1f10 | ||
|
|
8c9a41d72b |
No files matched your search
@@ -0,0 +1,45 @@
|
||||
name: Discover IDs
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: production
|
||||
|
||||
schedule:
|
||||
- cron: 0 */6 * * *
|
||||
|
||||
workflow_dispatch:
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
discover:
|
||||
name: Discover IDs
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
ref: production
|
||||
submodules: recursive
|
||||
token: ${{ secrets.GH_TOKEN }}
|
||||
|
||||
- name: Setup bun
|
||||
uses: oven-sh/setup-bun@v2
|
||||
|
||||
- name: Install dependencies
|
||||
run: bun install
|
||||
|
||||
- name: Setup Git
|
||||
run: |
|
||||
git config --global user.name "github-actions[bot]"
|
||||
git config --global user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
||||
|
||||
- name: Discover IDs
|
||||
run: bun run discover-ids
|
||||
env:
|
||||
PUBLIC_WARGAMING_APPLICATION_ID: ${{ secrets.PUBLIC_WARGAMING_APPLICATION_ID }}
|
||||
GH_TOKEN: ${{ secrets.IDS_TOKEN }}
|
||||
@@ -8,13 +8,23 @@ on:
|
||||
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
branch:
|
||||
description: Branch
|
||||
|
||||
type: choice
|
||||
required: true
|
||||
default: production
|
||||
|
||||
options:
|
||||
- production
|
||||
- main
|
||||
|
||||
environment:
|
||||
description: Environment
|
||||
|
||||
required: true
|
||||
# default: production
|
||||
default: beta
|
||||
type: choice
|
||||
required: true
|
||||
default: production
|
||||
|
||||
options:
|
||||
- development
|
||||
@@ -23,16 +33,42 @@ on:
|
||||
- preview
|
||||
- opentest
|
||||
|
||||
client_provider:
|
||||
description: Client provider
|
||||
|
||||
type: choice
|
||||
required: true
|
||||
default: steam
|
||||
|
||||
options:
|
||||
- steam
|
||||
- zip
|
||||
- wgpkg
|
||||
|
||||
client_source:
|
||||
description: Client source
|
||||
|
||||
type: string
|
||||
required: true
|
||||
default: 444200/windows
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
group: ${{ github.workflow }}-${{ inputs.environment || github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
# client
|
||||
STEAM_USERNAME: ${{ secrets.STEAM_USERNAME }}
|
||||
STEAM_PASSWORD: ${{ secrets.STEAM_PASSWORD }}
|
||||
CLIENT_PROVIDER: ${{ inputs.client_provider || 'steam' }}
|
||||
CLIENT_SOURCE: ${{ inputs.client_source || '444200/windows' }}
|
||||
CLIENT_DIR: ../../temp/game
|
||||
|
||||
# blitzkit
|
||||
PUBLIC_ENVIRONMENT: ${{ inputs.environment || 'beta' }}
|
||||
PUBLIC_ENVIRONMENT: ${{ inputs.environment || 'production' }}
|
||||
PUBLIC_PROMOTE_OPENTEST: false
|
||||
PUBLIC_STATIC_ASSET_BASE: https://assets.blitzkit.app
|
||||
PUBLIC_GUIDE_WEBSITE: https://guidesblitz.com
|
||||
@@ -41,7 +77,6 @@ env:
|
||||
WOTB_GLOSSARY: ${{ secrets.WOTB_GLOSSARY }}
|
||||
WOTB_GLOSSARY_DOMAIN: ${{ secrets.WOTB_GLOSSARY_DOMAIN }}
|
||||
WOTB_GLOSSARY_PATH: ${{ secrets.WOTB_GLOSSARY_PATH }}
|
||||
GAME_DIR: ../../temp/game
|
||||
|
||||
# google
|
||||
PUBLIC_GOOGLE_TAG_MANAGER_ID: ${{ secrets.PUBLIC_GOOGLE_TAG_MANAGER_ID }}
|
||||
@@ -49,12 +84,6 @@ env:
|
||||
# wargaming
|
||||
PUBLIC_WARGAMING_APPLICATION_ID: ${{ secrets.PUBLIC_WARGAMING_APPLICATION_ID }}
|
||||
|
||||
# steam
|
||||
STEAM_USERNAME: ${{ secrets.STEAM_USERNAME }}
|
||||
STEAM_PASSWORD: ${{ secrets.STEAM_PASSWORD }}
|
||||
STEAM_APP: 444200
|
||||
STEAM_OS: windows
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build website
|
||||
@@ -62,7 +91,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
fail-fast: true
|
||||
matrix:
|
||||
chunk: [default, api]
|
||||
|
||||
@@ -73,6 +102,7 @@ jobs:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
ref: ${{ inputs.branch || 'production' }}
|
||||
submodules: recursive
|
||||
token: ${{ secrets.GH_TOKEN }}
|
||||
|
||||
@@ -84,44 +114,16 @@ jobs:
|
||||
with:
|
||||
repo-token: ${{ secrets.GH_TOKEN }}
|
||||
|
||||
- name: Configure pages
|
||||
uses: actions/configure-pages@v6
|
||||
- name: Setup CLIs
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y aria2 libarchive-tools
|
||||
|
||||
- name: Install dependencies
|
||||
run: bun install
|
||||
|
||||
- name: Setup DepotDownloader
|
||||
run: |
|
||||
REPO_USER="SteamRE"
|
||||
REPO_NAME="DepotDownloader"
|
||||
TEMP="temp"
|
||||
|
||||
OUT="$TEMP/$REPO_NAME"
|
||||
ZIP="$TEMP/$REPO_NAME.zip"
|
||||
|
||||
URL=$(
|
||||
curl -s "https://api.github.com/repos/$REPO_USER/$REPO_NAME/releases/latest" \
|
||||
| jq -r '.assets[]
|
||||
| select(.name | contains("linux-x64"))
|
||||
| .browser_download_url' \
|
||||
| head -n 1
|
||||
)
|
||||
|
||||
mkdir -p "$TEMP"
|
||||
curl -L "$URL" -o "$ZIP"
|
||||
unzip -p "$ZIP" "$REPO_NAME" > "$OUT"
|
||||
rm "$ZIP"
|
||||
|
||||
chmod +x "$OUT"
|
||||
|
||||
- name: Download game
|
||||
run: |
|
||||
TEMP="temp"
|
||||
|
||||
DEPOT_DOWNLOADER="$TEMP/DepotDownloader"
|
||||
GAME="$TEMP/game"
|
||||
|
||||
$DEPOT_DOWNLOADER -os $STEAM_OS -app $STEAM_APP -username $STEAM_USERNAME -password $STEAM_PASSWORD -dir $GAME -max-downloads 256
|
||||
- name: Download Client
|
||||
run: bun run download-client
|
||||
|
||||
- name: Build
|
||||
run: bun run --bun build
|
||||
@@ -137,7 +139,7 @@ jobs:
|
||||
|
||||
- name: Trigger deployment
|
||||
|
||||
if: github.ref_name == 'production' || github.ref_name == 'infrastructure'
|
||||
if: ${{ github.ref == 'refs/heads/production' }}
|
||||
|
||||
env:
|
||||
TOKEN: ${{ secrets.GH_NODE_DEPLOY_TOKEN }}
|
||||
@@ -24,19 +24,18 @@ If you intend to contribute to the code, note that you may need to check out sen
|
||||
|
||||
## Environment Variables
|
||||
|
||||
| Name | Source | BlitzKit Default | Memo |
|
||||
| ------------------------------------------------------------- | -------------------------------------------------------------------------------- | ----------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `PUBLIC_WARGAMING_APPLICATION_ID` | [Wargaming Developer's Room](https://developers.wargaming.net/) | | Application ID needed to communicate with Wargaming APIs. |
|
||||
| `PUBLIC_PROMOTE_OPENTEST` | | `false` | Optional boolean dictating whether the website advertises [the opentest subdomain of BlitzKit](https://opentest.blitzkit.app/). |
|
||||
| `ALLOW_ROBOTS` | | `true` | Toggles between `Allow: /` and `Disallow: /` in the website's `/robots.txt`. This is usually `false` for all BlitzKit's subdomains. |
|
||||
| `WOTB_GLOSSARY`, `WOTB_GLOSSARY_DOMAIN`, `WOTB_GLOSSARY_PATH` | | | |
|
||||
| `PUBLIC_GOOGLE_TAG_MANAGER_ID` | [Google Tag Manager](https://tagmanager.google.com/) | `G-GL2JVHCGPQ` | Google Tag Manager's unique identifier for analytical purposes. |
|
||||
| `PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID` | [Google Analytics](https://analytics.google.com/) | `430711767` | Google Analytics' unique property ID for [BlitzKit's apex domain](https://blitzkit.app/) and subdomains. |
|
||||
| `GOOGLE_APPLICATION_CREDENTIALS` | [Google Cloud](https://cloud.google.com/) | | Google Cloud's API key, primarily used for ranking popular tanks and finding relevant tank review videos in Tankopedia. |
|
||||
| `PUBLIC_DISCORD_SERVER_ID` | [BlitzKit Discord Server](https://discord.gg/nDt7AjGJQH) | `734786591205359697` | BlitzKit Discord Server's id. |
|
||||
| `PUBLIC_ASSET_BASE` | [blitzkit/assets](https://github.com/blitzkit/assets) | `https://blitzkit.github.io/assets` | The root domain and path that serves the external assets like tank models and icons. |
|
||||
| `PUBLIC_GUIDE_WEBSITE` | [GuidesBlitz](https://guidesblitz.com/) | `https://guidesblitz.com` | The website that serves the encyclopedia-like content in BlitzKit. |
|
||||
| `SERVICING` | | `false` | Wether the website is down for servicing. |
|
||||
| `GH_TOKEN` | [GitHub Fine-Grained Tokens](https://github.com/settings/personal-access-tokens) | | The GitHub API key used for checking out private submodules and pushing content to the asset repository. |
|
||||
| `DATABASE_URL` | [CockroachDB](https://www.cockroachlabs.com/) | | The CockroachDB-SQL database URL used to link Wargaming and Discord users. |
|
||||
| `WOTB_DLC_CDN` | | | |
|
||||
| Name | Source | BlitzKit Default | Memo |
|
||||
| ------------------------------------------------------------- | -------------------------------------------------------------------------------- | ----------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `PUBLIC_WARGAMING_APPLICATION_ID` | [Wargaming Developer's Room](https://developers.wargaming.net/) | | Application ID needed to communicate with Wargaming APIs. |
|
||||
| `PUBLIC_PROMOTE_OPENTEST` | | `false` | Optional boolean dictating whether the website advertises [the opentest subdomain of BlitzKit](https://opentest.blitzkit.app/). |
|
||||
| `WOTB_GLOSSARY`, `WOTB_GLOSSARY_DOMAIN`, `WOTB_GLOSSARY_PATH` | | | |
|
||||
| `PUBLIC_GOOGLE_TAG_MANAGER_ID` | [Google Tag Manager](https://tagmanager.google.com/) | `G-GL2JVHCGPQ` | Google Tag Manager's unique identifier for analytical purposes. |
|
||||
| `PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID` | [Google Analytics](https://analytics.google.com/) | `430711767` | Google Analytics' unique property ID for [BlitzKit's apex domain](https://blitzkit.app/) and subdomains. |
|
||||
| `GOOGLE_APPLICATION_CREDENTIALS` | [Google Cloud](https://cloud.google.com/) | | Google Cloud's API key, primarily used for ranking popular tanks and finding relevant tank review videos in Tankopedia. |
|
||||
| `PUBLIC_DISCORD_SERVER_ID` | [BlitzKit Discord Server](https://discord.gg/nDt7AjGJQH) | `734786591205359697` | BlitzKit Discord Server's id. |
|
||||
| `PUBLIC_ASSET_BASE` | [blitzkit/assets](https://github.com/blitzkit/assets) | `https://blitzkit.github.io/assets` | The root domain and path that serves the external assets like tank models and icons. |
|
||||
| `PUBLIC_GUIDE_WEBSITE` | [GuidesBlitz](https://guidesblitz.com/) | `https://guidesblitz.com` | The website that serves the encyclopedia-like content in BlitzKit. |
|
||||
| `SERVICING` | | `false` | Wether the website is down for servicing. |
|
||||
| `GH_TOKEN` | [GitHub Fine-Grained Tokens](https://github.com/settings/personal-access-tokens) | | The GitHub API key used for checking out private submodules and pushing content to the asset repository. |
|
||||
| `DATABASE_URL` | [CockroachDB](https://www.cockroachlabs.com/) | | The CockroachDB-SQL database URL used to link Wargaming and Discord users. |
|
||||
| `WOTB_DLC_CDN` | | | |
|
||||
@@ -30,7 +30,7 @@
|
||||
"@octokit/plugin-throttling": "^11.0.1",
|
||||
"@octokit/rest": "^22.0.0",
|
||||
"@types/adm-zip": "^0.5.7",
|
||||
"@types/bun": "^1.3.1",
|
||||
"@types/bun": "^1.3.14",
|
||||
"@types/lodash-es": "^4.17.12",
|
||||
"@types/lz4js": "^0.2.1",
|
||||
"@types/three": "^0.180.0",
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
# BlitzKit 1.31.0
|
||||
|
||||
This update massively upgrades BlitzKit's graphical fidelity (while making it faster) and updates the way BlitzKit deploys updates, speeding up future versions.
|
||||
|
||||
## Features
|
||||
|
||||
- Improved the performance of the Tank Sandbox in Tankopedia
|
||||
- Reduced the number of lights by 25%
|
||||
- Reduced the resolution of shadows by 50%
|
||||
- Improved the graphical fidelity of tanks in the Tankopedia
|
||||
- Added soft contact shadows below tanks
|
||||
- Added sky and ground reflected lighting to the top and bottom of tanks
|
||||
- Removed the fog that used to darken tanks when zoomed far away
|
||||
- Made BlitzKitLand™ fade out circularly to hide the sharp edges
|
||||
- Pointed the lights 1.5m above the ground
|
||||
- This genuinely makes BlitzKit almost photo-realistic in my opinion
|
||||
- Non-PBR tanks are now lit up brighter to accommodate for their dark textures
|
||||
|
||||
## Fixes
|
||||
|
||||
- Fixed a bug where the ambient occlusion map (a measure of how dark a part of a tank gets due to low light bounces) was applied to the color of the tank directly, making many tanks appear dark even in direct light
|
||||
- Tanks with chinese characters now generate urls through transliteration
|
||||
|
||||
## Known Issues
|
||||
|
||||
- The flags found behind the selected tank in the tech tree section of the Tankopedia is offset incorrectly
|
||||
|
||||
## Technical Features
|
||||
|
||||
- BlitzKit can now calculate and store performance statistics and account details for up 10,000,000,000 players
|
||||
- This will help make the BlitzKit Performance tool more accurate, and play well with an upcoming, unannounced major feature
|
||||
|
||||
## Technical Changes
|
||||
|
||||
- The `production` branch now deploys updates to `blitzkit.app` instead of the `main` branch
|
||||
- `robots.txt` now disables indexing of BlitzKit variants based on the environment
|
||||
- The website is now compiled in "chunks" of which the `api` chunk now takes on the task of mangling what was previously stored in `assets3`
|
||||
- `assets3` will be removed in `1.31.1`, please migrate to the new `api` if you use any BlitzKit assets
|
||||
- Removed the `bot` and `app` packages
|
||||
- Removed Prisma
|
||||
@@ -0,0 +1,3 @@
|
||||
# BlitzKit 1.31.1
|
||||
|
||||
This update adds capabilities to release BlitzKit OpenTest and Preview.
|
||||
@@ -1,4 +1,7 @@
|
||||
{
|
||||
"robots": false,
|
||||
"canonical": "https://blitzkit.app",
|
||||
|
||||
"paths": {
|
||||
"default": null,
|
||||
"api": null
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
{
|
||||
"robots": false,
|
||||
"canonical": "https://blitzkit.app",
|
||||
|
||||
"paths": {
|
||||
"default": null,
|
||||
"api": "api"
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
{
|
||||
"robots": false,
|
||||
"canonical": "https://blitzkit.app",
|
||||
|
||||
"paths": {
|
||||
"default": null,
|
||||
"api": null
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
{
|
||||
"robots": false,
|
||||
"canonical": "https://blitzkit.app",
|
||||
|
||||
"paths": {
|
||||
"default": null,
|
||||
"api": null
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
{
|
||||
"robots": true,
|
||||
"canonical": "https://blitzkit.app",
|
||||
|
||||
"paths": {
|
||||
"default": null,
|
||||
"api": null
|
||||
|
||||
+5
-3
@@ -1,13 +1,15 @@
|
||||
{
|
||||
"name": "blitzkit",
|
||||
"version": "1.31.0",
|
||||
"version": "1.31.1",
|
||||
"license": "BlitzKit License",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "cd packages/website && bun run dev",
|
||||
"build": "cd packages/website && bun run build",
|
||||
"build:averages": "cd packages/scripts && bun run build:averages",
|
||||
"build:ids": "cd packages/scripts && bun run build:ids"
|
||||
"discover-ids": "cd packages/scripts && bun run discover-ids",
|
||||
"build-protos": "cd packages/scripts && bun run build-protos",
|
||||
"record-performance": "cd packages/scripts && bun run record-performance",
|
||||
"download-client": "cd packages/scripts && bun run download-client"
|
||||
},
|
||||
"type": "module",
|
||||
"workspaces": [
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
"@octokit/plugin-throttling": "^11.0.1",
|
||||
"@octokit/rest": "^22.0.0",
|
||||
"@types/adm-zip": "^0.5.7",
|
||||
"@types/bun": "^1.3.1",
|
||||
"@types/bun": "^1.3.14",
|
||||
"@types/lodash-es": "^4.17.12",
|
||||
"@types/lz4js": "^0.2.1",
|
||||
"@types/three": "^0.180.0",
|
||||
|
||||
@@ -1,28 +1,42 @@
|
||||
import { assertSecret } from "@blitzkit/core";
|
||||
|
||||
interface EnvironmentConfig {
|
||||
robots: boolean;
|
||||
canonical: string;
|
||||
paths: Record<string, string | null>;
|
||||
nodes: Record<string, string>;
|
||||
aliases: Record<string, string>;
|
||||
}
|
||||
|
||||
export const environments = import.meta.glob(
|
||||
"../../../../environments/*.json",
|
||||
{
|
||||
let hasReadEnvironments = false;
|
||||
const environments: Record<string, EnvironmentConfig> = {};
|
||||
|
||||
/**
|
||||
* This is set up this way to avoid errors in runtimes where
|
||||
* `import.meta.glob` does not exist.
|
||||
*/
|
||||
function readEnvironments() {
|
||||
if (hasReadEnvironments) return;
|
||||
|
||||
hasReadEnvironments = true;
|
||||
|
||||
const glob = import.meta.glob("../../../../environments/*.json", {
|
||||
eager: true,
|
||||
import: "default",
|
||||
},
|
||||
) as Record<string, EnvironmentConfig>;
|
||||
const root = "../../../../environments";
|
||||
}) as Record<string, EnvironmentConfig>;
|
||||
const root = "../../../../environments";
|
||||
|
||||
for (const key in environments) {
|
||||
const trimmed = key.slice(root.length + 1, -5);
|
||||
for (const key in glob) {
|
||||
const trimmed = key.slice(root.length + 1, -5);
|
||||
|
||||
environments[trimmed] = environments[key];
|
||||
delete environments[key];
|
||||
environments[trimmed] = glob[key];
|
||||
delete environments[key];
|
||||
}
|
||||
}
|
||||
|
||||
export function environmentConfig() {
|
||||
readEnvironments();
|
||||
|
||||
const environment = assertSecret(import.meta.env.PUBLIC_ENVIRONMENT);
|
||||
|
||||
if (!(environment in environments)) {
|
||||
|
||||
@@ -46,7 +46,15 @@ export abstract class AbstractVFS {
|
||||
return buffer;
|
||||
}
|
||||
|
||||
abstract dir(path: string): Promise<string[]>;
|
||||
protected abstract _dir(path: string): Promise<string[]>;
|
||||
|
||||
async dir(path: string) {
|
||||
const files = await this._dir(path);
|
||||
|
||||
return files.map((file) =>
|
||||
file.endsWith(".dvpl") ? file.slice(0, -5) : file,
|
||||
);
|
||||
}
|
||||
|
||||
async text(path: string) {
|
||||
const file = await this.file(path);
|
||||
@@ -63,7 +71,7 @@ export abstract class AbstractVFS {
|
||||
return this.xmlParser.parse(file) as Type;
|
||||
}
|
||||
|
||||
async _csv(text: string, options: Options = {}) {
|
||||
protected async _csv(text: string, options: Options = {}) {
|
||||
const parsed = parseCSV(text, options);
|
||||
return parsed;
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ export class LocalVFS extends AbstractVFS {
|
||||
return array;
|
||||
}
|
||||
|
||||
async dir(path: string) {
|
||||
async _dir(path: string) {
|
||||
try {
|
||||
return await readdir(`${this.base}/${path}`);
|
||||
} catch (_) {
|
||||
|
||||
@@ -35,7 +35,7 @@ export class MixedVFS extends AbstractVFS {
|
||||
throw new Error(`File not found: ${path}`);
|
||||
}
|
||||
|
||||
async dir(path: string) {
|
||||
async _dir(path: string) {
|
||||
const files = new Set<string>();
|
||||
|
||||
for (const vfs of this.vfses) {
|
||||
|
||||
@@ -89,7 +89,7 @@ export class SteamVFS extends AbstractVFS {
|
||||
return new Uint8Array(downloaded.file);
|
||||
}
|
||||
|
||||
async dir(path: string) {
|
||||
async _dir(path: string) {
|
||||
const parentSegments = path.split("/").length;
|
||||
const children = new Set<string>();
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ export class ZipVFS extends AbstractVFS {
|
||||
return new Uint8Array(arrayBuffer);
|
||||
}
|
||||
|
||||
async dir(path: string) {
|
||||
async _dir(path: string) {
|
||||
const parentSegments = path.split("/").length;
|
||||
const children = new Set<string>();
|
||||
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
import { times } from 'lodash-es';
|
||||
import { ReadStream, WriteStream } from './buffer';
|
||||
|
||||
export class DidsReadStream extends ReadStream {
|
||||
dids() {
|
||||
this.magic();
|
||||
this.header();
|
||||
return this.body();
|
||||
}
|
||||
|
||||
magic() {
|
||||
const magic = this.utf8(4);
|
||||
if (magic !== 'DIDS') {
|
||||
throw new Error(`Invalid DIDS magic number: "${magic}"`);
|
||||
}
|
||||
}
|
||||
|
||||
header() {
|
||||
return {
|
||||
version: this.uint16(),
|
||||
};
|
||||
}
|
||||
|
||||
body() {
|
||||
const count = this.uint32();
|
||||
return times(count, () => this.uint32());
|
||||
}
|
||||
}
|
||||
|
||||
export class DidsWriteStream extends WriteStream {
|
||||
dids(ids: number[]) {
|
||||
this.magic();
|
||||
this.header();
|
||||
this.body(ids);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
magic() {
|
||||
this.utf8('DIDS');
|
||||
}
|
||||
|
||||
header() {
|
||||
this.uint16(1);
|
||||
}
|
||||
|
||||
body(ids: number[]) {
|
||||
this.uint32(ids.length);
|
||||
ids.forEach((id) => this.uint32(id));
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,9 @@
|
||||
export * from './buffer';
|
||||
export * from './bufferToBigInt';
|
||||
export * from './dds';
|
||||
export * from './dids';
|
||||
export * from './pvr';
|
||||
export * from './rts';
|
||||
export * from './sc2';
|
||||
export * from './scg';
|
||||
export * from './scpg';
|
||||
export * from './windows';
|
||||
|
||||
export * from "./buffer";
|
||||
export * from "./bufferToBigInt";
|
||||
export * from "./dds";
|
||||
export * from "./pvr";
|
||||
export * from "./rts";
|
||||
export * from "./sc2";
|
||||
export * from "./scg";
|
||||
export * from "./scpg";
|
||||
export * from "./windows";
|
||||
@@ -37,10 +37,11 @@
|
||||
"d_1": "Ayer"
|
||||
},
|
||||
"branches": {
|
||||
"local": "DEV",
|
||||
"dev": "Beta",
|
||||
"opentest": "Prueba Abierta",
|
||||
"preview": "Avance"
|
||||
"beta": "Beta",
|
||||
"development": "Development",
|
||||
"opentest": "Prueba abierta",
|
||||
"preview": "Preview",
|
||||
"production": "Production"
|
||||
},
|
||||
"locales": {
|
||||
"en": "Ingles",
|
||||
@@ -184,467 +185,6 @@
|
||||
"cumulative_battle_life_time": "Tiempo total de batalla"
|
||||
}
|
||||
},
|
||||
"bot": {
|
||||
"common": {
|
||||
"errors": {
|
||||
"clan_not_found": "# Could not find clan\nCouldn't find \"{search}\". Try selecting a clan from the search result.",
|
||||
"player_not_found": "# Could not find user\nI couldn't find user \"{search}\". Try picking an user from the search result, typing in a valid username, or using the `/link` command.",
|
||||
"player_not_linked": "# Usa `/vincular` para empezar\n¡No sé quién eres, pero puedes decírmelo hoy!",
|
||||
"tank_name_not_found": "# Tank not found\nCould not find tank by the name \"{search}\".",
|
||||
"tank_id_not_found": "# Tank not found\nCould not find tank by the ID \"{search}\". Try typing the name of the tank instead of a number.",
|
||||
"no_tank_stats": "# No hay estadísticas de tanque disponibles\nEste jugador no tiene estadísticas disponibles. Este podría no ser el jugador que estás buscando.",
|
||||
"get_help": "Servidor de ayuda de Discord",
|
||||
"uncaught_error": "# ¡Blitzkrieg sufrió un error!\nLo sentimos mucho. Siéntete libre de [unirte al servidor oficial de Discord](https://discord.gg/nDt7AjGJQH) para obtener ayuda.",
|
||||
"preview": "# Este comando es una vista previa\n\nSolo puedes acceder a este comando en [el servidor oficial de Discord](https://discord.gg/nDt7AjGJQH). Generalmente este comando estará disponible pronto.",
|
||||
"query_too_small": "# Tu búsqueda es demasiado corta\nDebe ser por lo menos de 3 caracteres de largo.",
|
||||
"query_too_long": "# Tu búsqueda es demasiado larga\nDebe ser como mucho de 100 caracteres de largo."
|
||||
},
|
||||
"wn8": {
|
||||
"name": "WN8",
|
||||
"types": {
|
||||
"very_bad": "Muy Malo",
|
||||
"bad": "Malo",
|
||||
"below_average": "Debajo del Promedio",
|
||||
"average": "Promedio",
|
||||
"above_average": "Superior al Promedio",
|
||||
"good": "Bueno",
|
||||
"very_good": "Muy Bueno",
|
||||
"great": "Excelente",
|
||||
"unicum": "Unicum",
|
||||
"super_unicum": "Super Unicum"
|
||||
}
|
||||
},
|
||||
"subcommands": {
|
||||
"today": {
|
||||
"name": "Hoy",
|
||||
"description": "Hoy"
|
||||
},
|
||||
"30": {
|
||||
"name": "30",
|
||||
"description": "30 días"
|
||||
},
|
||||
"60": {
|
||||
"name": "60",
|
||||
"description": "60 días"
|
||||
},
|
||||
"90": {
|
||||
"name": "90",
|
||||
"description": "90 días"
|
||||
},
|
||||
"career": {
|
||||
"name": "carrera",
|
||||
"description": "Carrera"
|
||||
},
|
||||
"custom": {
|
||||
"name": "personalizado",
|
||||
"description": "Rango personalizado",
|
||||
"options": {
|
||||
"start": {
|
||||
"name": "comenzar",
|
||||
"description": "Comenzar en cantidad de días pasados desde hoy"
|
||||
},
|
||||
"end": {
|
||||
"name": "fin",
|
||||
"description": "Terminar en cantidad de días pasados desde hoy"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"options": {
|
||||
"clan": {
|
||||
"name": "clan",
|
||||
"description": "El nombre o etiqueta del clan"
|
||||
},
|
||||
"tank": {
|
||||
"name": "tanque",
|
||||
"description": "El tanque al cual conseguirle estadísticas"
|
||||
},
|
||||
"username": {
|
||||
"name": "nombre de usuario",
|
||||
"description": "El nombre de usuario de Blitz"
|
||||
},
|
||||
"filters": {
|
||||
"nation": {
|
||||
"name": "nación",
|
||||
"description": "Nación"
|
||||
},
|
||||
"class": {
|
||||
"name": "clase",
|
||||
"description": "Clase"
|
||||
},
|
||||
"type": {
|
||||
"name": "tipo",
|
||||
"description": "Tipo"
|
||||
}
|
||||
},
|
||||
"region": {
|
||||
"name": "región",
|
||||
"description": "Región"
|
||||
},
|
||||
"tier": {
|
||||
"name": "tier",
|
||||
"description": "Nivel",
|
||||
"choices": {
|
||||
"tier": "Tier {tier_1} - {tier_2}"
|
||||
}
|
||||
}
|
||||
},
|
||||
"periods": {
|
||||
"career": "Carrera",
|
||||
"today": "Hoy",
|
||||
"days": "{days} days",
|
||||
"custom": "{day_1} - {day_2} days"
|
||||
},
|
||||
"filters": {
|
||||
"none": "Sin filtros",
|
||||
"tier": "Tier {tier}"
|
||||
},
|
||||
"no_data": {
|
||||
"battles_in_period": "No hay batallas jugadas en este período",
|
||||
"battles_in_season": "No hay batallas jugadas en esta temporada",
|
||||
"players_in_period": "No hay jugadores en este período",
|
||||
"tanks_found": "No se encontraron tanques"
|
||||
},
|
||||
"buttons": {
|
||||
"refresh": "Actualizar"
|
||||
},
|
||||
"hero_stats": {
|
||||
"battles": "Batallas",
|
||||
"winrate": "Tasa de victorias",
|
||||
"damage": "Daño",
|
||||
"damage_ratio": "Relación de daño",
|
||||
"tier": "Nivel",
|
||||
"survival": "Supervivencia",
|
||||
"accuracy": "Precisión",
|
||||
"kills": "Bajas"
|
||||
}
|
||||
},
|
||||
"commands": {
|
||||
"dead": "# Stat Commands Are Dead\n\nThe BlitzKit Discord bot used to use BlitzStars to fetch periodic statistics. BlitzStars has enabled aggressive Cloudflare protections; hence, disabling BlitzKit from using BlitzStar's API. This has impacted the following commands:\n\n- `/stats`\n- `/today`\n- `/breakdown`\n- `/evolution`\n- `/full-stats`\n\nPlease use [Aftermath](<https://amth.one/invite>) as an alternative which is completely independent of BlitzStars. BlitzKit-hosted stat commands will return in the near future.",
|
||||
"replay": {
|
||||
"name": "repetición",
|
||||
"description": "Mostrar resultados de la repetición",
|
||||
"options": {
|
||||
"file": {
|
||||
"name": "file",
|
||||
"description": "Replay file"
|
||||
}
|
||||
}
|
||||
},
|
||||
"research": {
|
||||
"name": "desarollar",
|
||||
"description": "Enumera los gastos por investigar una línea",
|
||||
"options": {
|
||||
"target_tank": {
|
||||
"name": "tanque objetivo",
|
||||
"description": "El último tanque a investigar en la línea"
|
||||
},
|
||||
"starting_tank": {
|
||||
"name": "tanque de inicio",
|
||||
"description": "El tanque inicial en la línea (se deduce automáticamente si no se proporciona)"
|
||||
}
|
||||
},
|
||||
"body": {
|
||||
"subtitle": "Investigar",
|
||||
"total": "Total",
|
||||
"research": "Research: {cost}",
|
||||
"upgrades": "Upgrades: {cost}",
|
||||
"purchase": "Purchase: {cost}",
|
||||
"equipment": "Equipment: {cost}",
|
||||
"estimation": "# ¡Esto es una estimación!\n\nEsta lista podría incluir tanques ya investigados debido a la información errónea que proporciona Wargaming. Si puedes, prueba proporcionando un `tanque-inicial` de la línea al usar el comando."
|
||||
},
|
||||
"errors": {
|
||||
"non_tech_tree": "# {tank} is not on the tech tree\n\nYou cannot research a premium/collector tank.",
|
||||
"tier_1": "# {tank} is a tier I\n\nTier I tanks are always unlocked for free for all players.",
|
||||
"already_researched": "# {tank} is already researched\n\nTry providing a `starting-tank` when using the command to view the totals for a line you have already researched.",
|
||||
"start_end_equal": "# {tank} was provided twice\n\nMake sure `starting-tank` and `target-tank` are different.",
|
||||
"tanks_not_on_line": "# {tank_1} and {tank_2} are not on the same line\n\nMake sure `starting-tank` and `target-tank` are on the same tech-tree line.",
|
||||
"unordered": "# {tank_1} higher tiered to {tank_2}\n\nMake sure to provide {tank_2} as the `starting-tank` instead as it is the lower tiered tank."
|
||||
}
|
||||
},
|
||||
"about": {
|
||||
"name": "acerca",
|
||||
"description": "Toda la información que necesitas sobre el bot",
|
||||
"subcommands": {
|
||||
"commands": {
|
||||
"name": "comandos",
|
||||
"description": "Lista de todos los comandos y sus descripciones",
|
||||
"body": "# Comandos\n\nBlitzKit ofrece los siguientes comandos:\n\n"
|
||||
},
|
||||
"embeds": {
|
||||
"name": "embeds",
|
||||
"description": "Cómo funcionan los embeds"
|
||||
},
|
||||
"introduction": {
|
||||
"name": "introducción",
|
||||
"description": "Sobre el bot"
|
||||
},
|
||||
"invite": {
|
||||
"name": "invitar",
|
||||
"description": "Cómo invitar al bot"
|
||||
},
|
||||
"timezones": {
|
||||
"name": "zonas horarias",
|
||||
"description": "Cómo Blitzkrieg infiere y utiliza tu zona horaria"
|
||||
},
|
||||
"credits": {
|
||||
"name": "créditos",
|
||||
"description": "Personas que han ayudado a BlitzKit"
|
||||
}
|
||||
}
|
||||
},
|
||||
"breakdown": {
|
||||
"name": "resumen",
|
||||
"description": "Resumen de un período por tanques jugados",
|
||||
"body": {
|
||||
"total": "Total",
|
||||
"battles": "Batallas",
|
||||
"wn8": "WN8",
|
||||
"winrate": "Tasa de victorias",
|
||||
"damage": "Daño",
|
||||
"unknown_tank": "Unknown tank {id}"
|
||||
}
|
||||
},
|
||||
"debug": {
|
||||
"name": "depurar",
|
||||
"description": "Muestra más información sobre el bot",
|
||||
"body": {
|
||||
"title": "# Depuración\n\n",
|
||||
"version": "Versión",
|
||||
"shard": {
|
||||
"label": "Fragmentar",
|
||||
"default": "predeterminado"
|
||||
},
|
||||
"uptime": "Tiempo en línea"
|
||||
}
|
||||
},
|
||||
"evolution": {
|
||||
"name": "evolución",
|
||||
"description": "Evolución de estadísticas",
|
||||
"groups": {
|
||||
"player": {
|
||||
"name": "jugador",
|
||||
"description": "Estadísticas del jugador"
|
||||
},
|
||||
"tank": {
|
||||
"name": "tanque",
|
||||
"description": "Estadísticas del tanque"
|
||||
}
|
||||
}
|
||||
},
|
||||
"inactive": {
|
||||
"name": "inactivo",
|
||||
"description": "Enumera a todos los jugadores inactivos en un clan por encima de un umbral",
|
||||
"options": {
|
||||
"threshold": {
|
||||
"name": "umbral",
|
||||
"description": "The number of days inactive (default: {days} days)"
|
||||
}
|
||||
},
|
||||
"body": {
|
||||
"subtitle": "Inactive for {days}+ days",
|
||||
"listing": "{days} days"
|
||||
}
|
||||
},
|
||||
"full_stats": {
|
||||
"name": "estadísticas completas",
|
||||
"description": "Estadísticas completas del juego",
|
||||
"body": {
|
||||
"cards": {
|
||||
"games": {
|
||||
"title": "Partidas",
|
||||
"winrate": "Tasa de victorias",
|
||||
"battles": "Batallas",
|
||||
"wins_losses": "Victorias / derrotas"
|
||||
},
|
||||
"efficiency": {
|
||||
"title": "Eficiencia",
|
||||
"wn8": "WN8",
|
||||
"survival": "Supervivencia",
|
||||
"accuracy": "Precisión"
|
||||
},
|
||||
"lethality": {
|
||||
"title": "Letalidad",
|
||||
"average_damage": "Daño promedio",
|
||||
"damage_per_tier": "Daño por nivel",
|
||||
"damage_ratio": "Relación de daño",
|
||||
"average_kills": "Promedio de bajas"
|
||||
},
|
||||
"miscellaneous": {
|
||||
"title": "Misceláneo",
|
||||
"average_tier": "Nivel promedio",
|
||||
"average_spots": "Promedio de detecciones",
|
||||
"average_xp": "Promedio de XP",
|
||||
"kills_to_death_ratio": "Relación bajas-muertes"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"link": {
|
||||
"name": "vincular",
|
||||
"description": "Vincula tu cuenta de Blitz y Discord",
|
||||
"body": {
|
||||
"accounts_linked": "Cuentas vinculadas",
|
||||
"no_role_permissions": {
|
||||
"title": "{name} failed to verify",
|
||||
"description": "No tengo permiso para administrar roles."
|
||||
}
|
||||
},
|
||||
"embed": {
|
||||
"title": "¿Cuenta incorrecta?",
|
||||
"description": "Usa el comando de nuevo y selecciona un usuario de los resultados de búsqueda."
|
||||
}
|
||||
},
|
||||
"search_clans": {
|
||||
"name": "buscar clanes",
|
||||
"description": "Buscar clanes",
|
||||
"options": {
|
||||
"limit": {
|
||||
"name": "límite",
|
||||
"description": "The max number of clan results (default: {limit})"
|
||||
}
|
||||
},
|
||||
"body": {
|
||||
"title": "Clan search for {search} in region {region}",
|
||||
"no_results": "No se encontraron clanes"
|
||||
}
|
||||
},
|
||||
"search_players": {
|
||||
"name": "buscar jugadores",
|
||||
"description": "Buscar jugadores",
|
||||
"options": {
|
||||
"limit": {
|
||||
"name": "límite",
|
||||
"description": "The max number of player results (default: {limit})"
|
||||
}
|
||||
},
|
||||
"body": {
|
||||
"title": "Player search for {search} in region {region}",
|
||||
"no_results": "No se encontraron jugadores"
|
||||
}
|
||||
},
|
||||
"rating_leaderboard": {
|
||||
"name": "tabla de clasificación",
|
||||
"description": "Estadísticas de batallas de clasificatoria",
|
||||
"subcommands": {
|
||||
"neighbors": {
|
||||
"name": "vecinos",
|
||||
"description": "Jugadores vecinos en la tabla de posiciones"
|
||||
},
|
||||
"league": {
|
||||
"name": "liga",
|
||||
"description": "Mejores jugadores de una liga"
|
||||
}
|
||||
},
|
||||
"options": {
|
||||
"limit": {
|
||||
"name": "limite",
|
||||
"description": "How many neighbors to display (default: {count})"
|
||||
},
|
||||
"season": {
|
||||
"name": "temporada",
|
||||
"description": "Número de temporada (predeterminado: actual)",
|
||||
"choices": {
|
||||
"current": "{season} (current)"
|
||||
}
|
||||
},
|
||||
"league": {
|
||||
"name": "liga",
|
||||
"description": "La liga a mostrar"
|
||||
}
|
||||
},
|
||||
"body": {
|
||||
"top_players": "Top {count} players",
|
||||
"no_participation": "# {player} didn't play rating in season {season}\n\nThis player did not participate in this season or did not get past calibration.",
|
||||
"no_ongoing_season": "# No hay temporada en curso\n\nActualmente no hay ninguna temporada de clasificatoria.",
|
||||
"deleted_player": "Deleted {id}",
|
||||
"neighbors": "Vecinos de clasificatoria",
|
||||
"more": "+ {count} more"
|
||||
}
|
||||
},
|
||||
"today": {
|
||||
"name": "hoy",
|
||||
"description": "Tanques jugados hoy y estadísticas"
|
||||
},
|
||||
"stats": {
|
||||
"name": "estadísticas",
|
||||
"description": "Estadísticas rápidas para un período"
|
||||
},
|
||||
"owned_tanks": {
|
||||
"name": "tanques en propiedad",
|
||||
"description": "Muestra todos los tanques propios en un nivel",
|
||||
"body": {
|
||||
"title": "# {name}'s owned tier {tier} tanks\n\n"
|
||||
}
|
||||
},
|
||||
"permissions": {
|
||||
"name": "permisos",
|
||||
"description": "Comprueba si el bot tiene los permisos requeridos para funcionar",
|
||||
"body": {
|
||||
"title": "# Permissions\n\n{body}",
|
||||
"view_channels": "Ver canales: necesario para encontrar el mensaje en el cual el botón \"actualizar\" fue usado",
|
||||
"read_message_history": "Leer historial de mensajes: necesario para encontrar el mensaje a actualizar",
|
||||
"attach_files": "Adjuntar archivos: necesario para añadir imágenes a los comandos basados en estas",
|
||||
"external_emojis": "Emoticonos externos: necesario para añadir emoticonos de banderas nacionales y clases de tanque"
|
||||
}
|
||||
},
|
||||
"ping": {
|
||||
"name": "ping",
|
||||
"description": "Comprueba si el bot está vivo.",
|
||||
"body": {
|
||||
"pong": "Pong 🏓",
|
||||
"pong_with_time": "Pong 🏓 - {time}ms"
|
||||
},
|
||||
"subcommands": {
|
||||
"blitzkit": {
|
||||
"name": "blitzkit",
|
||||
"description": "Hacerle un ping a BlitzKit"
|
||||
},
|
||||
"wotb": {
|
||||
"name": "wotb",
|
||||
"description": "Hacerle un ping a World of Tanks Blitz"
|
||||
}
|
||||
}
|
||||
},
|
||||
"player_info": {
|
||||
"name": "info del jugador",
|
||||
"description": "Información básica sobre un jugador",
|
||||
"body": {
|
||||
"title": "{name}'s information",
|
||||
"nickname": "Apodo",
|
||||
"battles": "Batallas",
|
||||
"winrate": "Tasa de victorias",
|
||||
"account_id": "ID de cuenta",
|
||||
"created": "Creado",
|
||||
"last_battle": "Última batalla"
|
||||
}
|
||||
},
|
||||
"rating": {
|
||||
"name": "clasificatoria",
|
||||
"description": "Estadísticas de clasificatoria del jugador",
|
||||
"subcommands": {
|
||||
"today": {
|
||||
"name": "hoy",
|
||||
"description": "Estadísticas de clasificatoria de hoy"
|
||||
},
|
||||
"season": {
|
||||
"name": "temporada",
|
||||
"description": "Estadísticas de clasificatoria de esta temporada"
|
||||
}
|
||||
},
|
||||
"body": {
|
||||
"subtitle": {
|
||||
"today": "Estadísticas de clasificatoria de hoy",
|
||||
"season": "Estadísticas de clasificatoria de esta temporada"
|
||||
}
|
||||
},
|
||||
"errors": {
|
||||
"no_participation": "# {name} hasn't played rating\n\nThis player hasn't participated in the rating gamemode this season.",
|
||||
"unrecorded_stats": "# Estadísticas no disponibles actualmente\n\nWargaming podría estar sufriendo una caída del servidor. Si hay alguna temporada en curso, las estadísticas deberían estar disponibles en 24 horas."
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"website": {
|
||||
"redirect": {
|
||||
"title": "301: moved permanently",
|
||||
@@ -741,14 +281,6 @@
|
||||
}
|
||||
},
|
||||
"home": {
|
||||
"pwa": {
|
||||
"title": "Install the BlitzKit App",
|
||||
"new": "NEW",
|
||||
"checking": "Checking compatibility...",
|
||||
"instructions": "Instructions for Apple devices.",
|
||||
"install": "Install",
|
||||
"dismiss": "Dismiss"
|
||||
},
|
||||
"discord": {
|
||||
"join_short": "Join cool people!",
|
||||
"join_long": "Join super duper cool people!",
|
||||
|
||||
@@ -37,10 +37,11 @@
|
||||
"d_1": "Hier"
|
||||
},
|
||||
"branches": {
|
||||
"local": "dev",
|
||||
"dev": "beta",
|
||||
"opentest": "test ouvert",
|
||||
"preview": "aperçu"
|
||||
"beta": "Beta",
|
||||
"development": "Development",
|
||||
"opentest": "OpenTest",
|
||||
"preview": "Preview",
|
||||
"production": "Production"
|
||||
},
|
||||
"locales": {
|
||||
"en": "Anglais",
|
||||
@@ -184,467 +185,6 @@
|
||||
"cumulative_battle_life_time": "Total de temps de bataille"
|
||||
}
|
||||
},
|
||||
"bot": {
|
||||
"common": {
|
||||
"errors": {
|
||||
"clan_not_found": "# Impossible de trouver le clan\nImpossible de trouver «{search} ». Essayez de sélectionner un clan dans le résultat de la recherche.",
|
||||
"player_not_found": "# Impossible de trouver l'utilisateur\nJe n'ai pas pu trouver l'utilisateur \"{search}\". Essayez de choisir un utilisateur dans le résultat de la recherche, en tapant un nom d'utilisateur valide, ou en utilisant la commande `/link`.",
|
||||
"player_not_linked": "# Utilisez `/link` pour commencer\nJe ne sais pas qui vous êtes, mais vous pouvez me le dire aujourd'hui !",
|
||||
"tank_name_not_found": "# Char introuvable\nImpossible de trouver le char sous le nom \"{search}\".",
|
||||
"tank_id_not_found": "# Char introuvable\nImpossible de trouver le char avec l'ID \"{search}\". Essayez de taper le nom du char au lieu d'un nombre.",
|
||||
"no_tank_stats": "# Aucune statistique de tank disponible\nCe joueur n'a pas de statistiques disponibles. Ce n'est peut-être pas le joueur que vous cherchez.",
|
||||
"get_help": "Aidez le serveur Discord",
|
||||
"uncaught_error": "# Blitzkit a rencontré une erreur !\nNous sommes désolés de cela. N'hésitez pas à [rejoindre le serveur officiel Discord](https://discord.gg/nDt7AjGJQH) pour obtenir de l'aide.",
|
||||
"preview": "# Cette commande est en aperçu\n\nVous ne pouvez accéder à cette commande que dans [le serveur officiel Discord](https://discord.gg/nDt7AjGJQH). La commande sera généralement disponible sous peu.",
|
||||
"query_too_small": "# Votre recherche est trop courte\nVotre recherche doit comporter au moins 3 caractères.",
|
||||
"query_too_long": "# Votre recherche est trop longue\nVotre recherche doit comporter au maximum 100 caractères."
|
||||
},
|
||||
"wn8": {
|
||||
"name": "WN8",
|
||||
"types": {
|
||||
"very_bad": "Très nul",
|
||||
"bad": "Nul",
|
||||
"below_average": "En-dessous de la moyenne",
|
||||
"average": "Moyenne",
|
||||
"above_average": "Au-dessus de la moyenne",
|
||||
"good": "Bien",
|
||||
"very_good": "Très bien",
|
||||
"great": "Super",
|
||||
"unicum": "Unique",
|
||||
"super_unicum": "Super unique"
|
||||
}
|
||||
},
|
||||
"subcommands": {
|
||||
"today": {
|
||||
"name": "aujourd'hui",
|
||||
"description": "Aujourd'hui"
|
||||
},
|
||||
"30": {
|
||||
"name": "30",
|
||||
"description": "30 jours"
|
||||
},
|
||||
"60": {
|
||||
"name": "60",
|
||||
"description": "60 jours"
|
||||
},
|
||||
"90": {
|
||||
"name": "90",
|
||||
"description": "90 jours"
|
||||
},
|
||||
"career": {
|
||||
"name": "carrière",
|
||||
"description": "Carrière"
|
||||
},
|
||||
"custom": {
|
||||
"name": "personnaliser",
|
||||
"description": "Période spécifique",
|
||||
"options": {
|
||||
"start": {
|
||||
"name": "début",
|
||||
"description": "Commencer il y a un nombre de jours à partir d'aujourd'hui"
|
||||
},
|
||||
"end": {
|
||||
"name": "fin",
|
||||
"description": "Fin en nombre de jours à partir d'aujourd'hui"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"options": {
|
||||
"clan": {
|
||||
"name": "clan",
|
||||
"description": "Le nom ou le tag du clan"
|
||||
},
|
||||
"tank": {
|
||||
"name": "char",
|
||||
"description": "Le char pour obtenir des statistiques pour"
|
||||
},
|
||||
"username": {
|
||||
"name": "nom d'utilisateur",
|
||||
"description": "Le nom d'utilisateur Blitz du joueur"
|
||||
},
|
||||
"filters": {
|
||||
"nation": {
|
||||
"name": "pays",
|
||||
"description": "Pays"
|
||||
},
|
||||
"class": {
|
||||
"name": "classe",
|
||||
"description": "Classe"
|
||||
},
|
||||
"type": {
|
||||
"name": "type",
|
||||
"description": "Type"
|
||||
}
|
||||
},
|
||||
"region": {
|
||||
"name": "région",
|
||||
"description": "Région"
|
||||
},
|
||||
"tier": {
|
||||
"name": "rang",
|
||||
"description": "Rang",
|
||||
"choices": {
|
||||
"tier": "Rang {tier_}1 - {tier_}2"
|
||||
}
|
||||
}
|
||||
},
|
||||
"periods": {
|
||||
"career": "Carrière",
|
||||
"today": "Aujourd'hui",
|
||||
"days": "{days} jours",
|
||||
"custom": "{day_1} - {day_2} jours"
|
||||
},
|
||||
"filters": {
|
||||
"none": "Aucun filtre",
|
||||
"tier": "Rang {tier}"
|
||||
},
|
||||
"no_data": {
|
||||
"battles_in_period": "",
|
||||
"battles_in_season": "Aucune bataille jouée dans cette saison",
|
||||
"players_in_period": "Aucun joueur pendant cette période",
|
||||
"tanks_found": "Aucun char de trouver"
|
||||
},
|
||||
"buttons": {
|
||||
"refresh": "Actualiser"
|
||||
},
|
||||
"hero_stats": {
|
||||
"battles": "Batailles",
|
||||
"winrate": "Taux de victoires",
|
||||
"damage": "Dégâts",
|
||||
"damage_ratio": "Rapport de dégâts",
|
||||
"tier": "Rang",
|
||||
"survival": "Survie",
|
||||
"accuracy": "Précision",
|
||||
"kills": "Tués"
|
||||
}
|
||||
},
|
||||
"commands": {
|
||||
"dead": "# Stat Commands Are Dead\n\nThe BlitzKit Discord bot used to use BlitzStars to fetch periodic statistics. BlitzStars has enabled aggressive Cloudflare protections; hence, disabling BlitzKit from using BlitzStar's API. This has impacted the following commands:\n\n- `/stats`\n- `/today`\n- `/breakdown`\n- `/evolution`\n- `/full-stats`\n\nPlease use [Aftermath](<https://amth.one/invite>) as an alternative which is completely independent of BlitzStars. BlitzKit-hosted stat commands will return in the near future.",
|
||||
"replay": {
|
||||
"name": "rejouer",
|
||||
"description": "Afficher les résultats de la relecture",
|
||||
"options": {
|
||||
"file": {
|
||||
"name": "file",
|
||||
"description": "Replay file"
|
||||
}
|
||||
}
|
||||
},
|
||||
"research": {
|
||||
"name": "recherche",
|
||||
"description": "Liste des dépenses liées à la recherche d'une ligne",
|
||||
"options": {
|
||||
"target_tank": {
|
||||
"name": "char cible",
|
||||
"description": "Le dernier char à rechercher dans la ligne"
|
||||
},
|
||||
"starting_tank": {
|
||||
"name": "Char de départ",
|
||||
"description": ""
|
||||
}
|
||||
},
|
||||
"body": {
|
||||
"subtitle": "Recherche",
|
||||
"total": "Total",
|
||||
"research": "Recherche : {cost}",
|
||||
"upgrades": "Améliorations : {cost}",
|
||||
"purchase": "Achat : {cost}",
|
||||
"equipment": "Équipement : {cost}",
|
||||
"estimation": "# Ceci est une estimation !\n\nCette liste peut inclure des chars déjà recherchés en raison de l'information inexacte fournie par Wargaming. Essayez de fournir un `char de départ` depuis la ligne lorsque vous utilisez la commande si vous le pouvez."
|
||||
},
|
||||
"errors": {
|
||||
"non_tech_tree": "# {tank} n'est pas dans l'arbre technologique\n\nVous ne pouvez pas rechercher un char premium/de collection.",
|
||||
"tier_1": "# {tank} est un char de rang I\n\nLe char de rang 1 sont déverrouillé gratuitement pour tous les joueurs.",
|
||||
"already_researched": "# {tank} est déjà recherché\n\nEssayez de fournir un `char de départ` en utilisant la commande pour voir la progression d'une lignée.",
|
||||
"start_end_equal": "# {tank} a été fourni deux fois\n\nAssurez-vous que `starting-tank` et `target-tank` sont différents.",
|
||||
"tanks_not_on_line": "{tank_}1 et {tank_}2 ne sont pas sur la même ligne \n\nAssurez-vous que `starting-tank` et `target-tank` sont sur la même ligne d'arbre technologique.",
|
||||
"unordered": "# {tank_1} niveau supérieur à {tank_2}\n\nAssurez-vous de fournir {tank_2} comme le `starting-tank` à la place car c'est le char de niveau inférieur."
|
||||
}
|
||||
},
|
||||
"about": {
|
||||
"name": "à propos",
|
||||
"description": "Toutes les informations dont vous avez besoin sur le bot",
|
||||
"subcommands": {
|
||||
"commands": {
|
||||
"name": "commandes",
|
||||
"description": "Liste de toutes les commandes et leurs descriptions",
|
||||
"body": "# Commandes\n\nBlitzKit offre les commandes suivantes :\n\n"
|
||||
},
|
||||
"embeds": {
|
||||
"name": "intègre",
|
||||
"description": "Comment fonctionnent les intégrations"
|
||||
},
|
||||
"introduction": {
|
||||
"name": "introduction",
|
||||
"description": "À propos du bot"
|
||||
},
|
||||
"invite": {
|
||||
"name": "inviter",
|
||||
"description": "Comment inviter le bot"
|
||||
},
|
||||
"timezones": {
|
||||
"name": "fuseau horaire",
|
||||
"description": "Comment BlitzKit déduit et utilise votre fuseau horaire"
|
||||
},
|
||||
"credits": {
|
||||
"name": "crédits",
|
||||
"description": "Personnes qui ont aidé BlitzKit"
|
||||
}
|
||||
}
|
||||
},
|
||||
"breakdown": {
|
||||
"name": "décomposition",
|
||||
"description": "Répartition d'une période par chars joués",
|
||||
"body": {
|
||||
"total": "Total",
|
||||
"battles": "Batailles",
|
||||
"wn8": "WN8",
|
||||
"winrate": "Taux de victoires",
|
||||
"damage": "Dégâts",
|
||||
"unknown_tank": "Char {id} inconnu"
|
||||
}
|
||||
},
|
||||
"debug": {
|
||||
"name": "déboguer",
|
||||
"description": "Déboguer les informations sur le bot",
|
||||
"body": {
|
||||
"title": "# Debog\n\n",
|
||||
"version": "Version",
|
||||
"shard": {
|
||||
"label": "Fragment",
|
||||
"default": "par défaut"
|
||||
},
|
||||
"uptime": "Temps de fonctionnement"
|
||||
}
|
||||
},
|
||||
"evolution": {
|
||||
"name": "évolution",
|
||||
"description": "Évolution des statistiques",
|
||||
"groups": {
|
||||
"player": {
|
||||
"name": "joueur",
|
||||
"description": "Statistiques du joueur"
|
||||
},
|
||||
"tank": {
|
||||
"name": "char",
|
||||
"description": "Statistiques du char"
|
||||
}
|
||||
}
|
||||
},
|
||||
"inactive": {
|
||||
"name": "inactif",
|
||||
"description": "Liste tous les joueurs inactifs dans un clan au-dessus d'un seuil",
|
||||
"options": {
|
||||
"threshold": {
|
||||
"name": "seuil",
|
||||
"description": "Le nombre de jours inactifs (par défaut: {days} jours)"
|
||||
}
|
||||
},
|
||||
"body": {
|
||||
"subtitle": "Inactif depuis plus de {days} jours",
|
||||
"listing": "{days} jours"
|
||||
}
|
||||
},
|
||||
"full_stats": {
|
||||
"name": "statistiques complètes",
|
||||
"description": "Statistiques complètes en jeu",
|
||||
"body": {
|
||||
"cards": {
|
||||
"games": {
|
||||
"title": "Parties",
|
||||
"winrate": "Taux de victoires",
|
||||
"battles": "Batailles",
|
||||
"wins_losses": "Victoires/Défaites"
|
||||
},
|
||||
"efficiency": {
|
||||
"title": "Efficacité",
|
||||
"wn8": "WN8",
|
||||
"survival": "Survie",
|
||||
"accuracy": "Précision"
|
||||
},
|
||||
"lethality": {
|
||||
"title": "Létalité",
|
||||
"average_damage": "Dégâts moyens",
|
||||
"damage_per_tier": "Dégâts par tier",
|
||||
"damage_ratio": "Rapport de dégâts",
|
||||
"average_kills": "Destruction moyenne"
|
||||
},
|
||||
"miscellaneous": {
|
||||
"title": "Divers",
|
||||
"average_tier": "Tier moyen",
|
||||
"average_spots": "Repérage moyen",
|
||||
"average_xp": "Exp. Moyenne par bataille",
|
||||
"kills_to_death_ratio": "Rapport tués/morts"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"link": {
|
||||
"name": "lien",
|
||||
"description": "Lier votre compte Blitz et Discord",
|
||||
"body": {
|
||||
"accounts_linked": "Comptes liés",
|
||||
"no_role_permissions": {
|
||||
"title": "La vérification de {name} a échouée",
|
||||
"description": "Je n'ai pas l'autorisation de gérer les rôles."
|
||||
}
|
||||
},
|
||||
"embed": {
|
||||
"title": "Compte invalide ?",
|
||||
"description": "Utilisez à nouveau la commande et sélectionnez un nom d'utilisateur à partir des résultats de recherche."
|
||||
}
|
||||
},
|
||||
"search_clans": {
|
||||
"name": "clans de recherche",
|
||||
"description": "Rechercher des clans",
|
||||
"options": {
|
||||
"limit": {
|
||||
"name": "limite",
|
||||
"description": "Nombre maximum de résultats du clan (par défaut: {limit})"
|
||||
}
|
||||
},
|
||||
"body": {
|
||||
"title": "Recherche de clan {search} dans la région {region}",
|
||||
"no_results": "Pas de clan trouvé"
|
||||
}
|
||||
},
|
||||
"search_players": {
|
||||
"name": "recherche de joueur",
|
||||
"description": "Recherche des joueurs",
|
||||
"options": {
|
||||
"limit": {
|
||||
"name": "limite",
|
||||
"description": "Le nombre maximum de résultats de joueur (par défaut: {limit})"
|
||||
}
|
||||
},
|
||||
"body": {
|
||||
"title": "Recherche de {search} dans la région {region}",
|
||||
"no_results": "Pas de joueur de trouvé"
|
||||
}
|
||||
},
|
||||
"rating_leaderboard": {
|
||||
"name": "Classement de côté",
|
||||
"description": "Statistiques des batailles de cotés",
|
||||
"subcommands": {
|
||||
"neighbors": {
|
||||
"name": "voisins",
|
||||
"description": "Joueurs voisins dans le classement"
|
||||
},
|
||||
"league": {
|
||||
"name": "ligue",
|
||||
"description": "Meilleurs joueurs d'une ligue"
|
||||
}
|
||||
},
|
||||
"options": {
|
||||
"limit": {
|
||||
"name": "limite",
|
||||
"description": "Combien de voisins afficher (par défaut : {count})"
|
||||
},
|
||||
"season": {
|
||||
"name": "saison",
|
||||
"description": "Numéro de saison (défaut : courant)",
|
||||
"choices": {
|
||||
"current": "{season} (actuel)"
|
||||
}
|
||||
},
|
||||
"league": {
|
||||
"name": "ligue",
|
||||
"description": "La ligue à afficher"
|
||||
}
|
||||
},
|
||||
"body": {
|
||||
"top_players": "Top {count} joueurs",
|
||||
"no_participation": "# {player} n'a pas joué de cotées dans la saison {season}\n\nCe joueur n'a pas participé à cette saison ou n'a pas dépassé l'étalonnage.",
|
||||
"no_ongoing_season": "Pas de saison en cours\n\nIl n'y a pas de saison de notation en cours actuellement.",
|
||||
"deleted_player": "{id} supprimé",
|
||||
"neighbors": "évaluer les voisins",
|
||||
"more": "+ {count} plus"
|
||||
}
|
||||
},
|
||||
"today": {
|
||||
"name": "aujourd'hui",
|
||||
"description": "Les chars et les statistiques joués aujourd'hui"
|
||||
},
|
||||
"stats": {
|
||||
"name": "statistiques",
|
||||
"description": "Statistiques rapides pour une période"
|
||||
},
|
||||
"owned_tanks": {
|
||||
"name": "chars possédés",
|
||||
"description": "Affiche tous les chars d'un niveau",
|
||||
"body": {
|
||||
"title": "# Les chars du palier {tier} possédés par {name}"
|
||||
}
|
||||
},
|
||||
"permissions": {
|
||||
"name": "permissions",
|
||||
"description": "Vérifie si le bot a les permissions nécessaires pour fonctionner",
|
||||
"body": {
|
||||
"title": "# Permissions\n\n{body}",
|
||||
"view_channels": "Afficher les canaux : nécessaire pour trouver le message sur lequel le bouton d'actualisation a été utilisé",
|
||||
"read_message_history": "Lire l'historique des messages : nécessaire pour trouver le message à rafraîchir",
|
||||
"attach_files": "Joindre des fichiers : nécessaire pour ajouter des images à des commandes basées sur l'image",
|
||||
"external_emojis": "Émoticônes externes: nécessaire pour ajouter des drapeaux nationaux et des émojis de classe de char"
|
||||
}
|
||||
},
|
||||
"ping": {
|
||||
"name": "ping",
|
||||
"description": "Vérifiez si le bot est en vie.",
|
||||
"body": {
|
||||
"pong": "Pong 🏓",
|
||||
"pong_with_time": "Pong 🏓 - {time}ms"
|
||||
},
|
||||
"subcommands": {
|
||||
"blitzkit": {
|
||||
"name": "blitzkit",
|
||||
"description": "Ping blitzkit"
|
||||
},
|
||||
"wotb": {
|
||||
"name": "wotb",
|
||||
"description": "Ping World of Tanks Blitz"
|
||||
}
|
||||
}
|
||||
},
|
||||
"player_info": {
|
||||
"name": "info-joueur",
|
||||
"description": "Informations de base sur un joueur",
|
||||
"body": {
|
||||
"title": "Informations de {name}",
|
||||
"nickname": "Pseudo",
|
||||
"battles": "Batailles",
|
||||
"winrate": "Taux de victoires",
|
||||
"account_id": "Account ID",
|
||||
"created": "Créé",
|
||||
"last_battle": "Dernière bataille"
|
||||
}
|
||||
},
|
||||
"rating": {
|
||||
"name": "côtée",
|
||||
"description": "Statistiques des batailles cotées du joueur",
|
||||
"subcommands": {
|
||||
"today": {
|
||||
"name": "aujourd'hui",
|
||||
"description": "Statistiques des batailles cotées d'aujourd'hui"
|
||||
},
|
||||
"season": {
|
||||
"name": "saison",
|
||||
"description": "Statistiques des batailles cotées de cette saison"
|
||||
}
|
||||
},
|
||||
"body": {
|
||||
"subtitle": {
|
||||
"today": "Statistiques de batailles cotées d'aujourd'hui",
|
||||
"season": "Statistiques de batailles cotées cette saison"
|
||||
}
|
||||
},
|
||||
"errors": {
|
||||
"no_participation": "# {name} n’a pas joué en cotée\n\nCe joueur n’a pas participé au mode cotée cette saison.",
|
||||
"unrecorded_stats": "# Statistiques actuellement indisponibles\n\nWargaming rencontre peut-être une interruption de service.\nSi une saison est en cours, les statistiques devraient être disponibles sous 24 heures."
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"website": {
|
||||
"redirect": {
|
||||
"title": "301 : déplacé définitivement",
|
||||
@@ -741,14 +281,6 @@
|
||||
}
|
||||
},
|
||||
"home": {
|
||||
"pwa": {
|
||||
"title": "Install the BlitzKit App",
|
||||
"new": "NEW",
|
||||
"checking": "Checking compatibility...",
|
||||
"instructions": "Instructions for Apple devices.",
|
||||
"install": "Install",
|
||||
"dismiss": "Dismiss"
|
||||
},
|
||||
"discord": {
|
||||
"join_short": "Join cool people!",
|
||||
"join_long": "Join super duper cool people!",
|
||||
|
||||
@@ -37,10 +37,11 @@
|
||||
"d_1": "昨日"
|
||||
},
|
||||
"branches": {
|
||||
"local": "開発",
|
||||
"dev": "ベータ版",
|
||||
"opentest": "オープンテスト",
|
||||
"preview": "プレビュー"
|
||||
"beta": "Beta",
|
||||
"development": "Development",
|
||||
"opentest": "OpenTest",
|
||||
"preview": "Preview",
|
||||
"production": "Production"
|
||||
},
|
||||
"locales": {
|
||||
"en": "英語",
|
||||
@@ -184,467 +185,6 @@
|
||||
"cumulative_battle_life_time": "総戦闘時間"
|
||||
}
|
||||
},
|
||||
"bot": {
|
||||
"common": {
|
||||
"errors": {
|
||||
"clan_not_found": "",
|
||||
"player_not_found": "# ユーザーが見つかりませんでした\nユーザー「{search}」が見つかりませんでした。検索結果からユーザーを選択するか、有効なユーザー名を入力するか、/link コマンドを使用してください。",
|
||||
"player_not_linked": "# `/link`を使用して始めましょう\nはじめまして!あなたが誰か、私に教えてください。",
|
||||
"tank_name_not_found": "# Tank not found\nCould not find tank by the name \"{search}\".",
|
||||
"tank_id_not_found": "# 車両が見つかりません\nID「{search}」の戦車が見つかりませんでした。数字ではなく戦車の名前を入力してみてください。",
|
||||
"no_tank_stats": "# 利用可能な車輌統計がありません\nこのプレイヤーには利用可能な統計がありません。あなたが探しているプレイヤーではない可能性があります。",
|
||||
"get_help": "Discordサーバーに参加する",
|
||||
"uncaught_error": "# BlitzKitがエラーに遭遇しました!\n申し訳ありません。お気軽に[公式Discordサーバー](https://discord.gg/nDt7AjGJQH)にお問い合わせください。",
|
||||
"preview": "このコマンドは現在[公式Discardサーバー](https://discord.gg/nDt7AjGJQH)でのみ利用可能です。間もなく全体で利用可能になります。",
|
||||
"query_too_small": "# 単語が短すぎます\n検索には少なくとも3文字が含まれている必要があります。",
|
||||
"query_too_long": "# 単語が長すぎます\n検索は最大で100文字までです。"
|
||||
},
|
||||
"wn8": {
|
||||
"name": "WN8",
|
||||
"types": {
|
||||
"very_bad": "Very bad",
|
||||
"bad": "Bad",
|
||||
"below_average": "Below average",
|
||||
"average": "Average",
|
||||
"above_average": "Above average",
|
||||
"good": "Good",
|
||||
"very_good": "Very good",
|
||||
"great": "Great",
|
||||
"unicum": "Unicum",
|
||||
"super_unicum": "Super unicum"
|
||||
}
|
||||
},
|
||||
"subcommands": {
|
||||
"today": {
|
||||
"name": "today",
|
||||
"description": "Today"
|
||||
},
|
||||
"30": {
|
||||
"name": "30",
|
||||
"description": "30日"
|
||||
},
|
||||
"60": {
|
||||
"name": "60",
|
||||
"description": "60日"
|
||||
},
|
||||
"90": {
|
||||
"name": "90",
|
||||
"description": "90日"
|
||||
},
|
||||
"career": {
|
||||
"name": "総合戦績",
|
||||
"description": "Career"
|
||||
},
|
||||
"custom": {
|
||||
"name": "カスタム",
|
||||
"description": "Custom range",
|
||||
"options": {
|
||||
"start": {
|
||||
"name": "開始",
|
||||
"description": "Start in number of days ago from today"
|
||||
},
|
||||
"end": {
|
||||
"name": "end",
|
||||
"description": "End in number of days ago from today"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"options": {
|
||||
"clan": {
|
||||
"name": "クラン",
|
||||
"description": "クラン名もしくはタグ"
|
||||
},
|
||||
"tank": {
|
||||
"name": "車輌",
|
||||
"description": "統計を得る車輌"
|
||||
},
|
||||
"username": {
|
||||
"name": "ユーザー名",
|
||||
"description": "プレイヤーのBlitzユーザー名"
|
||||
},
|
||||
"filters": {
|
||||
"nation": {
|
||||
"name": "国家",
|
||||
"description": "国家"
|
||||
},
|
||||
"class": {
|
||||
"name": "",
|
||||
"description": "Class"
|
||||
},
|
||||
"type": {
|
||||
"name": "type",
|
||||
"description": "Type"
|
||||
}
|
||||
},
|
||||
"region": {
|
||||
"name": "地域",
|
||||
"description": "地域"
|
||||
},
|
||||
"tier": {
|
||||
"name": "tier",
|
||||
"description": "Tier",
|
||||
"choices": {
|
||||
"tier": "Tier {tier_1} - {tier_2}"
|
||||
}
|
||||
}
|
||||
},
|
||||
"periods": {
|
||||
"career": "Career",
|
||||
"today": "Today",
|
||||
"days": "{days} days",
|
||||
"custom": "{day_1} - {day_2} days"
|
||||
},
|
||||
"filters": {
|
||||
"none": "フィルターなし",
|
||||
"tier": "Tier {tier}"
|
||||
},
|
||||
"no_data": {
|
||||
"battles_in_period": "No battles played in this period",
|
||||
"battles_in_season": "No battles played in this season",
|
||||
"players_in_period": "No players in this period",
|
||||
"tanks_found": "No tanks found"
|
||||
},
|
||||
"buttons": {
|
||||
"refresh": "Refresh"
|
||||
},
|
||||
"hero_stats": {
|
||||
"battles": "戦闘数",
|
||||
"winrate": "勝率",
|
||||
"damage": "ダメージ",
|
||||
"damage_ratio": "ダメージ率",
|
||||
"tier": "Tier",
|
||||
"survival": "生存",
|
||||
"accuracy": "命中率",
|
||||
"kills": "撃破"
|
||||
}
|
||||
},
|
||||
"commands": {
|
||||
"dead": "# Stat Commands Are Dead\n\nThe BlitzKit Discord bot used to use BlitzStars to fetch periodic statistics. BlitzStars has enabled aggressive Cloudflare protections; hence, disabling BlitzKit from using BlitzStar's API. This has impacted the following commands:\n\n- `/stats`\n- `/today`\n- `/breakdown`\n- `/evolution`\n- `/full-stats`\n\nPlease use [Aftermath](<https://amth.one/invite>) as an alternative which is completely independent of BlitzStars. BlitzKit-hosted stat commands will return in the near future.",
|
||||
"replay": {
|
||||
"name": "replay",
|
||||
"description": "Display replay results",
|
||||
"options": {
|
||||
"file": {
|
||||
"name": "file",
|
||||
"description": "Replay file"
|
||||
}
|
||||
}
|
||||
},
|
||||
"research": {
|
||||
"name": "研究",
|
||||
"description": "Lists the expenses in researching a line",
|
||||
"options": {
|
||||
"target_tank": {
|
||||
"name": "target-tank",
|
||||
"description": "The final tank to research in the line"
|
||||
},
|
||||
"starting_tank": {
|
||||
"name": "starting-tank",
|
||||
"description": "The starting tank in the line (inferred automatically if not provided)"
|
||||
}
|
||||
},
|
||||
"body": {
|
||||
"subtitle": "Research",
|
||||
"total": "トータル",
|
||||
"research": "Research: {cost}",
|
||||
"upgrades": "Upgrades: {cost}",
|
||||
"purchase": "Purchase: {cost}",
|
||||
"equipment": "Equipment: {cost}",
|
||||
"estimation": "# This is an estimation!\n\nThis list may include already researched tanks because of the inaccurate information Wargaming provides. Try providing a `starting-tank` from the line when using the command if you can."
|
||||
},
|
||||
"errors": {
|
||||
"non_tech_tree": "# {tank} is not on the tech tree\n\nYou cannot research a premium/collector tank.",
|
||||
"tier_1": "# {tank} is a tier I\n\nTier I tanks are always unlocked for free for all players.",
|
||||
"already_researched": "# {tank} is already researched\n\nTry providing a `starting-tank` when using the command to view the totals for a line you have already researched.",
|
||||
"start_end_equal": "# {tank} was provided twice\n\nMake sure `starting-tank` and `target-tank` are different.",
|
||||
"tanks_not_on_line": "# {tank_1} and {tank_2} are not on the same line\n\nMake sure `starting-tank` and `target-tank` are on the same tech-tree line.",
|
||||
"unordered": "# {tank_1} higher tiered to {tank_2}\n\nMake sure to provide {tank_2} as the `starting-tank` instead as it is the lower tiered tank."
|
||||
}
|
||||
},
|
||||
"about": {
|
||||
"name": "about",
|
||||
"description": "botについての情報の全て",
|
||||
"subcommands": {
|
||||
"commands": {
|
||||
"name": "コマンド",
|
||||
"description": "全コマンドのリストと説明",
|
||||
"body": "# コマンド\nBlitzKitは以下のコマンドを提供します:"
|
||||
},
|
||||
"embeds": {
|
||||
"name": "埋め込み",
|
||||
"description": "埋め込みがどう機能するか"
|
||||
},
|
||||
"introduction": {
|
||||
"name": "introduction",
|
||||
"description": "botについて"
|
||||
},
|
||||
"invite": {
|
||||
"name": "招待",
|
||||
"description": "botを招待する方法"
|
||||
},
|
||||
"timezones": {
|
||||
"name": "タイムゾーン",
|
||||
"description": "How BlitzKit infers and uses your timezone"
|
||||
},
|
||||
"credits": {
|
||||
"name": "クレジット",
|
||||
"description": "BlitzKitを支援した人々"
|
||||
}
|
||||
}
|
||||
},
|
||||
"breakdown": {
|
||||
"name": "breakdown",
|
||||
"description": "A period's breakdown by tanks played",
|
||||
"body": {
|
||||
"total": "トータル",
|
||||
"battles": "戦闘数",
|
||||
"wn8": "WN8",
|
||||
"winrate": "勝率",
|
||||
"damage": "ダメージ",
|
||||
"unknown_tank": "不明な車両{id}"
|
||||
}
|
||||
},
|
||||
"debug": {
|
||||
"name": "debug",
|
||||
"description": "Debug information about the bot",
|
||||
"body": {
|
||||
"title": "# Debug\n\n",
|
||||
"version": "Version",
|
||||
"shard": {
|
||||
"label": "Shard",
|
||||
"default": "default"
|
||||
},
|
||||
"uptime": "Uptime"
|
||||
}
|
||||
},
|
||||
"evolution": {
|
||||
"name": "evolution",
|
||||
"description": "Evolution of statistics",
|
||||
"groups": {
|
||||
"player": {
|
||||
"name": "player",
|
||||
"description": "Player statistics"
|
||||
},
|
||||
"tank": {
|
||||
"name": "車輌",
|
||||
"description": "Tank statistics"
|
||||
}
|
||||
}
|
||||
},
|
||||
"inactive": {
|
||||
"name": "inactive",
|
||||
"description": "Lists all inactive players in a clan above a threshold",
|
||||
"options": {
|
||||
"threshold": {
|
||||
"name": "threshold",
|
||||
"description": "The number of days inactive (default: {days} days)"
|
||||
}
|
||||
},
|
||||
"body": {
|
||||
"subtitle": "Inactive for {days}+ days",
|
||||
"listing": "{days} days"
|
||||
}
|
||||
},
|
||||
"full_stats": {
|
||||
"name": "full-stats",
|
||||
"description": "Full in-game statistics",
|
||||
"body": {
|
||||
"cards": {
|
||||
"games": {
|
||||
"title": "Games",
|
||||
"winrate": "勝率",
|
||||
"battles": "戦闘数",
|
||||
"wins_losses": "Wins / losses"
|
||||
},
|
||||
"efficiency": {
|
||||
"title": "Efficiency",
|
||||
"wn8": "WN8",
|
||||
"survival": "生存",
|
||||
"accuracy": "精度"
|
||||
},
|
||||
"lethality": {
|
||||
"title": "Lethality",
|
||||
"average_damage": "Average damage",
|
||||
"damage_per_tier": "Damage per tier",
|
||||
"damage_ratio": "ダメージ比",
|
||||
"average_kills": "Average kills"
|
||||
},
|
||||
"miscellaneous": {
|
||||
"title": "Miscellaneous",
|
||||
"average_tier": "Average tier",
|
||||
"average_spots": "Average spots",
|
||||
"average_xp": "Average XP",
|
||||
"kills_to_death_ratio": "撃破/被撃破比"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"link": {
|
||||
"name": "link",
|
||||
"description": "Links your Blitz and Discord account",
|
||||
"body": {
|
||||
"accounts_linked": "Accounts linked",
|
||||
"no_role_permissions": {
|
||||
"title": "{name} failed to verify",
|
||||
"description": "I don't have the permission to manage roles."
|
||||
}
|
||||
},
|
||||
"embed": {
|
||||
"title": "Incorrect account?",
|
||||
"description": "Use the command again and select a username from the search results."
|
||||
}
|
||||
},
|
||||
"search_clans": {
|
||||
"name": "search-clans",
|
||||
"description": "Search clans",
|
||||
"options": {
|
||||
"limit": {
|
||||
"name": "limit",
|
||||
"description": "The max number of clan results (default: {limit})"
|
||||
}
|
||||
},
|
||||
"body": {
|
||||
"title": "Clan search for {search} in region {region}",
|
||||
"no_results": "No clans found"
|
||||
}
|
||||
},
|
||||
"search_players": {
|
||||
"name": "search-players",
|
||||
"description": "Search players",
|
||||
"options": {
|
||||
"limit": {
|
||||
"name": "limit",
|
||||
"description": "The max number of player results (default: {limit})"
|
||||
}
|
||||
},
|
||||
"body": {
|
||||
"title": "Player search for {search} in region {region}",
|
||||
"no_results": "No players found"
|
||||
}
|
||||
},
|
||||
"rating_leaderboard": {
|
||||
"name": "rating-leaderboard",
|
||||
"description": "Rating battles statistics",
|
||||
"subcommands": {
|
||||
"neighbors": {
|
||||
"name": "neighbors",
|
||||
"description": "Neighboring players on the leaderboard"
|
||||
},
|
||||
"league": {
|
||||
"name": "league",
|
||||
"description": "Top players of a league"
|
||||
}
|
||||
},
|
||||
"options": {
|
||||
"limit": {
|
||||
"name": "limit",
|
||||
"description": "How many neighbors to display (default: {count})"
|
||||
},
|
||||
"season": {
|
||||
"name": "season",
|
||||
"description": "Season number (default: current)",
|
||||
"choices": {
|
||||
"current": "{season} (current)"
|
||||
}
|
||||
},
|
||||
"league": {
|
||||
"name": "league",
|
||||
"description": "The league to display"
|
||||
}
|
||||
},
|
||||
"body": {
|
||||
"top_players": "Top {count} players",
|
||||
"no_participation": "# {player} didn't play rating in season {season}\n\nThis player did not participate in this season or did not get past calibration.",
|
||||
"no_ongoing_season": "# No ongoing season\n\nThere isn't a currently running rating season.",
|
||||
"deleted_player": "Deleted {id}",
|
||||
"neighbors": "Rating neighbors",
|
||||
"more": "+ {count} more"
|
||||
}
|
||||
},
|
||||
"today": {
|
||||
"name": "今日",
|
||||
"description": "Today's played tanks and statistics"
|
||||
},
|
||||
"stats": {
|
||||
"name": "",
|
||||
"description": "Quick statistics for a period"
|
||||
},
|
||||
"owned_tanks": {
|
||||
"name": "owned-tanks",
|
||||
"description": "Shows all own tanks in a tier",
|
||||
"body": {
|
||||
"title": "# {name}'s owned tier {tier} tanks\n\n"
|
||||
}
|
||||
},
|
||||
"permissions": {
|
||||
"name": "permissions",
|
||||
"description": "Checks wether the bot has the required permissions to function",
|
||||
"body": {
|
||||
"title": "# Permissions\n\n{body}",
|
||||
"view_channels": "View channels: needed to find the message the refresh button was used on",
|
||||
"read_message_history": "Read message history: needed to find the message to refresh",
|
||||
"attach_files": "Attach files: needed to add images to image-based commands",
|
||||
"external_emojis": "External emojis: needed to add national flags and tank class emojis"
|
||||
}
|
||||
},
|
||||
"ping": {
|
||||
"name": "ping",
|
||||
"description": "Check wether the bot is alive.",
|
||||
"body": {
|
||||
"pong": "Pong 🏓",
|
||||
"pong_with_time": "Pong 🏓 - {time}ms"
|
||||
},
|
||||
"subcommands": {
|
||||
"blitzkit": {
|
||||
"name": "blitzkit",
|
||||
"description": "Ping BlitzKit"
|
||||
},
|
||||
"wotb": {
|
||||
"name": "wotb",
|
||||
"description": "Ping World of Tanks Blitz"
|
||||
}
|
||||
}
|
||||
},
|
||||
"player_info": {
|
||||
"name": "player-info",
|
||||
"description": "Basic information about a player",
|
||||
"body": {
|
||||
"title": "{name}'s information",
|
||||
"nickname": "Nickname",
|
||||
"battles": "戦闘数",
|
||||
"winrate": "勝率",
|
||||
"account_id": "Account ID",
|
||||
"created": "Created",
|
||||
"last_battle": "Last battle"
|
||||
}
|
||||
},
|
||||
"rating": {
|
||||
"name": "rating",
|
||||
"description": "Rating player's statistics",
|
||||
"subcommands": {
|
||||
"today": {
|
||||
"name": "今日",
|
||||
"description": "Today's rating statistics"
|
||||
},
|
||||
"season": {
|
||||
"name": "season",
|
||||
"description": "This season's rating statistics"
|
||||
}
|
||||
},
|
||||
"body": {
|
||||
"subtitle": {
|
||||
"today": "Today's rating statistics",
|
||||
"season": "This season's rating statistics"
|
||||
}
|
||||
},
|
||||
"errors": {
|
||||
"no_participation": "# {name} hasn't played rating\n\nThis player hasn't participated in the rating gamemode this season.",
|
||||
"unrecorded_stats": "# Statistics currently unavailable\n\nWargaming may be currently be facing server downtime. If there is an on-going season, statistics should be available withing 24 hours."
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"website": {
|
||||
"redirect": {
|
||||
"title": "301: moved permanently",
|
||||
@@ -741,14 +281,6 @@
|
||||
}
|
||||
},
|
||||
"home": {
|
||||
"pwa": {
|
||||
"title": "Install the BlitzKit App",
|
||||
"new": "NEW",
|
||||
"checking": "Checking compatibility...",
|
||||
"instructions": "Instructions for Apple devices.",
|
||||
"install": "Install",
|
||||
"dismiss": "Dismiss"
|
||||
},
|
||||
"discord": {
|
||||
"join_short": "Join cool people!",
|
||||
"join_long": "Join super duper cool people!",
|
||||
|
||||
@@ -37,10 +37,11 @@
|
||||
"d_1": "Wczoraj"
|
||||
},
|
||||
"branches": {
|
||||
"local": "dev",
|
||||
"dev": "beta",
|
||||
"opentest": "otwarty test",
|
||||
"preview": "podgląd"
|
||||
"beta": "Beta",
|
||||
"development": "Development",
|
||||
"opentest": "OpenTest",
|
||||
"preview": "Preview",
|
||||
"production": "Production"
|
||||
},
|
||||
"locales": {
|
||||
"en": "Angielski",
|
||||
@@ -184,467 +185,6 @@
|
||||
"cumulative_battle_life_time": "Całkowity czas bitwy"
|
||||
}
|
||||
},
|
||||
"bot": {
|
||||
"common": {
|
||||
"errors": {
|
||||
"clan_not_found": "# Could not find clan\nCouldn't find \"{search}\". Try selecting a clan from the search result.",
|
||||
"player_not_found": "# Could not find user\nI couldn't find user \"{search}\". Try picking an user from the search result, typing in a valid username, or using the `/link` command.",
|
||||
"player_not_linked": "# Użyj `/link` aby zacząć\nNie wiem, kim jesteś, ale możesz mi dziś powiedzieć!",
|
||||
"tank_name_not_found": "# Tank not found\nCould not find tank by the name \"{search}\".",
|
||||
"tank_id_not_found": "# Tank not found\nCould not find tank by the ID \"{search}\". Try typing the name of the tank instead of a number.",
|
||||
"no_tank_stats": "# Brak dostępnych statystyk czołgów\nTen gracz nie ma żadnych dostępnych statystyk. Może to nie być gracz, którego szukasz.",
|
||||
"get_help": "Pomóż serwerowi Discord",
|
||||
"uncaught_error": "# BlitzKit wpadł w błąd!\nPrzepraszamy za to. Możesz [dołączyć do oficjalnego serwera Discord](https://discord.gg/nDt7AjGJQH), aby uzyskać pomoc.",
|
||||
"preview": "# Ta komenda jest w podglądzie\n\nMożesz uzyskać dostęp do tej komendy tylko na [oficjalnym serwerze Discorda](https://discord.gg/nDt7AjGJQH). Polecenie będzie ogólnie dostępne wkrótce.",
|
||||
"query_too_small": "# Twoje wyszukiwanie jest zbyt krótkie\nTwoje wyszukiwanie musi mieć co najmniej 3 znaki.",
|
||||
"query_too_long": "# Twoje wyszukiwanie jest zbyt długie\nTwoje wyszukiwanie musi mieć maksymalnie 100 znaków."
|
||||
},
|
||||
"wn8": {
|
||||
"name": "WN8",
|
||||
"types": {
|
||||
"very_bad": "Bardzo złe",
|
||||
"bad": "Złe",
|
||||
"below_average": "Poniżej średniej",
|
||||
"average": "Średnia",
|
||||
"above_average": "Powyżej średniej",
|
||||
"good": "Dobrze",
|
||||
"very_good": "Bardzo dobrze",
|
||||
"great": "Świetne",
|
||||
"unicum": "Unikalny",
|
||||
"super_unicum": "Bardzo unikalny"
|
||||
}
|
||||
},
|
||||
"subcommands": {
|
||||
"today": {
|
||||
"name": "dziś",
|
||||
"description": "Dziś"
|
||||
},
|
||||
"30": {
|
||||
"name": "30",
|
||||
"description": "30 dni"
|
||||
},
|
||||
"60": {
|
||||
"name": "60",
|
||||
"description": "60 dni"
|
||||
},
|
||||
"90": {
|
||||
"name": "90",
|
||||
"description": "90 dni"
|
||||
},
|
||||
"career": {
|
||||
"name": "kariera",
|
||||
"description": "Kariera"
|
||||
},
|
||||
"custom": {
|
||||
"name": "custom",
|
||||
"description": "Zakres niestandardowy",
|
||||
"options": {
|
||||
"start": {
|
||||
"name": "start",
|
||||
"description": "Rozpocznij od dnia dzisiejszego"
|
||||
},
|
||||
"end": {
|
||||
"name": "zakończ",
|
||||
"description": "Zakończ od dnia dzisiejszego"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"options": {
|
||||
"clan": {
|
||||
"name": "klan",
|
||||
"description": "Wpisz nazwę klanu lub tag"
|
||||
},
|
||||
"tank": {
|
||||
"name": "czołg",
|
||||
"description": "Czołg do pobrania statystyk"
|
||||
},
|
||||
"username": {
|
||||
"name": "nazwa użytkownika",
|
||||
"description": "Nazwa użytkownika Blitz gracza"
|
||||
},
|
||||
"filters": {
|
||||
"nation": {
|
||||
"name": "naród",
|
||||
"description": "Naród"
|
||||
},
|
||||
"class": {
|
||||
"name": "klasa",
|
||||
"description": "Klasa"
|
||||
},
|
||||
"type": {
|
||||
"name": "rodzaj",
|
||||
"description": "Rodzaj"
|
||||
}
|
||||
},
|
||||
"region": {
|
||||
"name": "region",
|
||||
"description": "Region"
|
||||
},
|
||||
"tier": {
|
||||
"name": "poziom",
|
||||
"description": "Poziom",
|
||||
"choices": {
|
||||
"tier": "Tier {tier_1} - {tier_2}"
|
||||
}
|
||||
}
|
||||
},
|
||||
"periods": {
|
||||
"career": "Kariera",
|
||||
"today": "Dzisiaj",
|
||||
"days": "{days} days",
|
||||
"custom": "{day_1} - {day_2} days"
|
||||
},
|
||||
"filters": {
|
||||
"none": "Brak filtrów",
|
||||
"tier": "Tier {tier}"
|
||||
},
|
||||
"no_data": {
|
||||
"battles_in_period": "Brak bitew w tym okresie",
|
||||
"battles_in_season": "Brak bitew w tym sezonie",
|
||||
"players_in_period": "Brak graczy w tym okresie",
|
||||
"tanks_found": "Nie znaleziono czołgu"
|
||||
},
|
||||
"buttons": {
|
||||
"refresh": "Odśwież"
|
||||
},
|
||||
"hero_stats": {
|
||||
"battles": "Bitwy",
|
||||
"winrate": "Zwycięstwa",
|
||||
"damage": "Obrażenia",
|
||||
"damage_ratio": "Współczynnik obrażeń",
|
||||
"tier": "Poziom",
|
||||
"survival": "Przeżycie",
|
||||
"accuracy": "Celność",
|
||||
"kills": "Zabójstwa"
|
||||
}
|
||||
},
|
||||
"commands": {
|
||||
"dead": "# Stat Commands Are Dead\n\nThe BlitzKit Discord bot used to use BlitzStars to fetch periodic statistics. BlitzStars has enabled aggressive Cloudflare protections; hence, disabling BlitzKit from using BlitzStar's API. This has impacted the following commands:\n\n- `/stats`\n- `/today`\n- `/breakdown`\n- `/evolution`\n- `/full-stats`\n\nPlease use [Aftermath](<https://amth.one/invite>) as an alternative which is completely independent of BlitzStars. BlitzKit-hosted stat commands will return in the near future.",
|
||||
"replay": {
|
||||
"name": "powtórz",
|
||||
"description": "Wyświetl wyniki powtórki",
|
||||
"options": {
|
||||
"file": {
|
||||
"name": "file",
|
||||
"description": "Replay file"
|
||||
}
|
||||
}
|
||||
},
|
||||
"research": {
|
||||
"name": "badanie",
|
||||
"description": "Wyświetla wydatki na badanie linii",
|
||||
"options": {
|
||||
"target_tank": {
|
||||
"name": "docelowy czołg",
|
||||
"description": "Ostatni czołg do badań w linii"
|
||||
},
|
||||
"starting_tank": {
|
||||
"name": "czołg rozpoczynający",
|
||||
"description": "Czołg początkowy w linii (automatycznie, jeżeli nie jest dostarczony)"
|
||||
}
|
||||
},
|
||||
"body": {
|
||||
"subtitle": "Rozpocznij badania",
|
||||
"total": "Całkowity",
|
||||
"research": "Research: {cost}",
|
||||
"upgrades": "Upgrades: {cost}",
|
||||
"purchase": "Purchase: {cost}",
|
||||
"equipment": "Equipment: {cost}",
|
||||
"estimation": "# To jest szacunek!\n\nTa lista może zawierać już zbadane czołgi z powodu niedokładnych informacji dostarczanych przez Wargaming. Spróbuj podać `starting-tank` z wiersza podczas używania polecenia, jeśli możesz."
|
||||
},
|
||||
"errors": {
|
||||
"non_tech_tree": "# {tank} is not on the tech tree\n\nYou cannot research a premium/collector tank.",
|
||||
"tier_1": "# {tank} is a tier I\n\nTier I tanks are always unlocked for free for all players.",
|
||||
"already_researched": "# {tank} is already researched\n\nTry providing a `starting-tank` when using the command to view the totals for a line you have already researched.",
|
||||
"start_end_equal": "# {tank} was provided twice\n\nMake sure `starting-tank` and `target-tank` are different.",
|
||||
"tanks_not_on_line": "# {tank_1} and {tank_2} are not on the same line\n\nMake sure `starting-tank` and `target-tank` are on the same tech-tree line.",
|
||||
"unordered": "# {tank_1} higher tiered to {tank_2}\n\nMake sure to provide {tank_2} as the `starting-tank` instead as it is the lower tiered tank."
|
||||
}
|
||||
},
|
||||
"about": {
|
||||
"name": "opis",
|
||||
"description": "Wszystkie informacje na temat bota",
|
||||
"subcommands": {
|
||||
"commands": {
|
||||
"name": "komendy",
|
||||
"description": "Lista wszystkich poleceń i ich opisów",
|
||||
"body": "# Polecenia\n\nBlitzKit oferuje następujące polecenia:\n\n"
|
||||
},
|
||||
"embeds": {
|
||||
"name": "osadzenie",
|
||||
"description": "Jak działają osadzone"
|
||||
},
|
||||
"introduction": {
|
||||
"name": "wprowadzenie",
|
||||
"description": "O bocie"
|
||||
},
|
||||
"invite": {
|
||||
"name": "zaproszenie",
|
||||
"description": "Jak zaprosić bota"
|
||||
},
|
||||
"timezones": {
|
||||
"name": "strefy czasowe",
|
||||
"description": "W jaki sposób BlitzKit wnioskuje i wykorzystuje Twoją strefę czasową"
|
||||
},
|
||||
"credits": {
|
||||
"name": "uznania",
|
||||
"description": "Ludzie, którzy pomogli BlitzKit"
|
||||
}
|
||||
}
|
||||
},
|
||||
"breakdown": {
|
||||
"name": "podział",
|
||||
"description": "Podział przez okres według rozgrywanych czołgów",
|
||||
"body": {
|
||||
"total": "Ogółem",
|
||||
"battles": "Bitwy",
|
||||
"wn8": "WN8",
|
||||
"winrate": "Śr. wygranych",
|
||||
"damage": "Uszkodzenia",
|
||||
"unknown_tank": "Unknown tank {id}"
|
||||
}
|
||||
},
|
||||
"debug": {
|
||||
"name": "debugowanie",
|
||||
"description": "Debugowanie informacji o botu",
|
||||
"body": {
|
||||
"title": "# Debug\n\n",
|
||||
"version": "Wersja",
|
||||
"shard": {
|
||||
"label": "Fragment",
|
||||
"default": "domyślne"
|
||||
},
|
||||
"uptime": "Czas działania"
|
||||
}
|
||||
},
|
||||
"evolution": {
|
||||
"name": "rozwój",
|
||||
"description": "Rozwój statystyk",
|
||||
"groups": {
|
||||
"player": {
|
||||
"name": "gracz",
|
||||
"description": "Statystyki gracza"
|
||||
},
|
||||
"tank": {
|
||||
"name": "czołg",
|
||||
"description": "Statystyki czołgu"
|
||||
}
|
||||
}
|
||||
},
|
||||
"inactive": {
|
||||
"name": "inactive",
|
||||
"description": "Lists all inactive players in a clan above a threshold",
|
||||
"options": {
|
||||
"threshold": {
|
||||
"name": "threshold",
|
||||
"description": "The number of days inactive (default: {days} days)"
|
||||
}
|
||||
},
|
||||
"body": {
|
||||
"subtitle": "Inactive for {days}+ days",
|
||||
"listing": "{days} days"
|
||||
}
|
||||
},
|
||||
"full_stats": {
|
||||
"name": "full-stats",
|
||||
"description": "Full in-game statistics",
|
||||
"body": {
|
||||
"cards": {
|
||||
"games": {
|
||||
"title": "Games",
|
||||
"winrate": "Śr. wygranych",
|
||||
"battles": "Bitwy",
|
||||
"wins_losses": "Zwycięstwa / porażki"
|
||||
},
|
||||
"efficiency": {
|
||||
"title": "Efficiency",
|
||||
"wn8": "WN8",
|
||||
"survival": "Przeżycie",
|
||||
"accuracy": "Skuteczność"
|
||||
},
|
||||
"lethality": {
|
||||
"title": "Lethality",
|
||||
"average_damage": "Średnie uszkodzenia",
|
||||
"damage_per_tier": "Damage per tier",
|
||||
"damage_ratio": "Współczynnik obrażeń",
|
||||
"average_kills": "Average kills"
|
||||
},
|
||||
"miscellaneous": {
|
||||
"title": "Miscellaneous",
|
||||
"average_tier": "Średni poziom",
|
||||
"average_spots": "Average spots",
|
||||
"average_xp": "Average XP",
|
||||
"kills_to_death_ratio": "Stosunek zabójstw do śmierci"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"link": {
|
||||
"name": "link",
|
||||
"description": "Links your Blitz and Discord account",
|
||||
"body": {
|
||||
"accounts_linked": "Accounts linked",
|
||||
"no_role_permissions": {
|
||||
"title": "{name} failed to verify",
|
||||
"description": "I don't have the permission to manage roles."
|
||||
}
|
||||
},
|
||||
"embed": {
|
||||
"title": "Incorrect account?",
|
||||
"description": "Use the command again and select a username from the search results."
|
||||
}
|
||||
},
|
||||
"search_clans": {
|
||||
"name": "search-clans",
|
||||
"description": "Search clans",
|
||||
"options": {
|
||||
"limit": {
|
||||
"name": "",
|
||||
"description": "The max number of clan results (default: {limit})"
|
||||
}
|
||||
},
|
||||
"body": {
|
||||
"title": "Clan search for {search} in region {region}",
|
||||
"no_results": "No clans found"
|
||||
}
|
||||
},
|
||||
"search_players": {
|
||||
"name": "search-players",
|
||||
"description": "Search players",
|
||||
"options": {
|
||||
"limit": {
|
||||
"name": "",
|
||||
"description": "The max number of player results (default: {limit})"
|
||||
}
|
||||
},
|
||||
"body": {
|
||||
"title": "Player search for {search} in region {region}",
|
||||
"no_results": "No players found"
|
||||
}
|
||||
},
|
||||
"rating_leaderboard": {
|
||||
"name": "rating-leaderboard",
|
||||
"description": "Rating battles statistics",
|
||||
"subcommands": {
|
||||
"neighbors": {
|
||||
"name": "neighbors",
|
||||
"description": "Neighboring players on the leaderboard"
|
||||
},
|
||||
"league": {
|
||||
"name": "league",
|
||||
"description": "Najlepsi gracze ligi"
|
||||
}
|
||||
},
|
||||
"options": {
|
||||
"limit": {
|
||||
"name": "",
|
||||
"description": "How many neighbors to display (default: {count})"
|
||||
},
|
||||
"season": {
|
||||
"name": "season",
|
||||
"description": "Season number (default: current)",
|
||||
"choices": {
|
||||
"current": "{season} (current)"
|
||||
}
|
||||
},
|
||||
"league": {
|
||||
"name": "league",
|
||||
"description": "The league to display"
|
||||
}
|
||||
},
|
||||
"body": {
|
||||
"top_players": "Top {count} players",
|
||||
"no_participation": "# {player} didn't play rating in season {season}\n\nThis player did not participate in this season or did not get past calibration.",
|
||||
"no_ongoing_season": "# No ongoing season\n\nThere isn't a currently running rating season.",
|
||||
"deleted_player": "Deleted {id}",
|
||||
"neighbors": "Rating neighbors",
|
||||
"more": "+ {count} more"
|
||||
}
|
||||
},
|
||||
"today": {
|
||||
"name": "dzisiaj",
|
||||
"description": "Dzisiejsze zagrane czołgami i statystyki"
|
||||
},
|
||||
"stats": {
|
||||
"name": "stats",
|
||||
"description": "Szybkie statystyki na okres"
|
||||
},
|
||||
"owned_tanks": {
|
||||
"name": "posiadane czołgi",
|
||||
"description": "Pokazuje wszystkie własne czołgi na poziomie",
|
||||
"body": {
|
||||
"title": "# {name}'s owned tier {tier} tanks\n\n"
|
||||
}
|
||||
},
|
||||
"permissions": {
|
||||
"name": "uprawnienia",
|
||||
"description": "Sprawdza, czy bot ma wymagane uprawnienia do funkcji",
|
||||
"body": {
|
||||
"title": "# Permissions\n\n{body}",
|
||||
"view_channels": "Wyświetl kanały: potrzebne do znalezienia wiadomości użyty przycisk odświeżania",
|
||||
"read_message_history": "Przeczytaj historię wiadomości: potrzebne do znalezienia wiadomości do odświeżenia",
|
||||
"attach_files": "Dołącz pliki: potrzebne do dodawania obrazów do komend opartych na obrazach",
|
||||
"external_emojis": "Zewnętrzne emotikony: potrzebne do dodania flagi krajowych i emotikonów klasy zbiorników"
|
||||
}
|
||||
},
|
||||
"ping": {
|
||||
"name": "ping",
|
||||
"description": "Sprawdź, czy bot żyje.",
|
||||
"body": {
|
||||
"pong": "Pong 🏓",
|
||||
"pong_with_time": "Pong 🏓 - {time}ms"
|
||||
},
|
||||
"subcommands": {
|
||||
"blitzkit": {
|
||||
"name": "blitzkit",
|
||||
"description": "Ping BlitzKit"
|
||||
},
|
||||
"wotb": {
|
||||
"name": "wotb",
|
||||
"description": "Ping World of Tanks Blitz"
|
||||
}
|
||||
}
|
||||
},
|
||||
"player_info": {
|
||||
"name": "informacje o graczu",
|
||||
"description": "Podstawowe informacje o graczu",
|
||||
"body": {
|
||||
"title": "{name}'s information",
|
||||
"nickname": "Nick",
|
||||
"battles": "Bitwy",
|
||||
"winrate": "Śr. wygranych",
|
||||
"account_id": "ID konta",
|
||||
"created": "Stworzony",
|
||||
"last_battle": "Ostatnia bitwa"
|
||||
}
|
||||
},
|
||||
"rating": {
|
||||
"name": "klasyfikacja",
|
||||
"description": "Statystyki klasyfikacji gracza",
|
||||
"subcommands": {
|
||||
"today": {
|
||||
"name": "dzisiaj",
|
||||
"description": "Dzisiejsze statystyki klasyfikacji"
|
||||
},
|
||||
"season": {
|
||||
"name": "sezon",
|
||||
"description": "Statystyki klasyfikacji w tym sezonie"
|
||||
}
|
||||
},
|
||||
"body": {
|
||||
"subtitle": {
|
||||
"today": "Dzisiejsze statystyki klasyfikacji",
|
||||
"season": "Statystyki klasyfikacji w tym sezonie"
|
||||
}
|
||||
},
|
||||
"errors": {
|
||||
"no_participation": "# {name} hasn't played rating\n\nThis player hasn't participated in the rating gamemode this season.",
|
||||
"unrecorded_stats": "# Statistics currently unavailable\n\nWargaming may be currently be facing server downtime. If there is an on-going season, statistics should be available withing 24 hours."
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"website": {
|
||||
"redirect": {
|
||||
"title": "301: moved permanently",
|
||||
@@ -741,14 +281,6 @@
|
||||
}
|
||||
},
|
||||
"home": {
|
||||
"pwa": {
|
||||
"title": "Install the BlitzKit App",
|
||||
"new": "NEW",
|
||||
"checking": "Checking compatibility...",
|
||||
"instructions": "Instructions for Apple devices.",
|
||||
"install": "Install",
|
||||
"dismiss": "Dismiss"
|
||||
},
|
||||
"discord": {
|
||||
"join_short": "Join cool people!",
|
||||
"join_long": "Join super duper cool people!",
|
||||
|
||||
@@ -37,10 +37,11 @@
|
||||
"d_1": "Ontem"
|
||||
},
|
||||
"branches": {
|
||||
"local": "dev",
|
||||
"dev": "beta",
|
||||
"opentest": "testeaberto",
|
||||
"preview": "visualização"
|
||||
"beta": "Beta",
|
||||
"development": "Development",
|
||||
"opentest": "TesteAberto",
|
||||
"preview": "Preview",
|
||||
"production": "Production"
|
||||
},
|
||||
"locales": {
|
||||
"en": "Inglês",
|
||||
@@ -184,467 +185,6 @@
|
||||
"cumulative_battle_life_time": "Tempo de batalha total"
|
||||
}
|
||||
},
|
||||
"bot": {
|
||||
"common": {
|
||||
"errors": {
|
||||
"clan_not_found": "# Could not find clan\nCouldn't find \"{search}\". Try selecting a clan from the search result.",
|
||||
"player_not_found": "# Could not find user\nI couldn't find user \"{search}\". Try picking an user from the search result, typing in a valid username, or using the `/link` command.",
|
||||
"player_not_linked": "Digite \"/link\" para começar.\nEu posso não saber quem é você, mas pode-me dizer hoje sobre isso!",
|
||||
"tank_name_not_found": "# Tank not found\nCould not find tank by the name \"{search}\".",
|
||||
"tank_id_not_found": "# Tank not found\nCould not find tank by the ID \"{search}\". Try typing the name of the tank instead of a number.",
|
||||
"no_tank_stats": "# Nenhuma estatística de tanques disponível\nEsse jogador não tem as suas estatísticas disponíveis. Talvez esse pode não ser o jogador que procura.",
|
||||
"get_help": "Servidor de Ajuda no Discord",
|
||||
"uncaught_error": "# O BlitzKit apresentou um erro!\nSentimos muito por isso. Sinta-se a vontade para [entrar no servidor oficial no Discord]\n(https://discord.gg/nDt7AjGJQH) para conseguir ajuda.",
|
||||
"preview": "# Este comando está na pré-visualização\n\nVocê só pode acessar este comando no [servidor oficial do Discord](https://discord.gg/nDt7AjGJQH). O comando estará geralmente disponível em breve.",
|
||||
"query_too_small": "# Sua pesquisa é muito curta\nSua pesquisa deve ter pelo menos 3 caracteres.",
|
||||
"query_too_long": "# Sua pesquisa é muito longa\nSua pesquisa deve ter no máximo 100 caracteres."
|
||||
},
|
||||
"wn8": {
|
||||
"name": "WN8",
|
||||
"types": {
|
||||
"very_bad": "Muito ruim",
|
||||
"bad": "Ruim",
|
||||
"below_average": "Abaixo da média",
|
||||
"average": "Na média",
|
||||
"above_average": "Acima da média",
|
||||
"good": "Bom",
|
||||
"very_good": "Muito bom",
|
||||
"great": "Ótimo",
|
||||
"unicum": "Unicum",
|
||||
"super_unicum": "Super unicum"
|
||||
}
|
||||
},
|
||||
"subcommands": {
|
||||
"today": {
|
||||
"name": "hoje",
|
||||
"description": "Hoje"
|
||||
},
|
||||
"30": {
|
||||
"name": "30",
|
||||
"description": "30 dias"
|
||||
},
|
||||
"60": {
|
||||
"name": "60",
|
||||
"description": "60 dias"
|
||||
},
|
||||
"90": {
|
||||
"name": "90",
|
||||
"description": "90 dias"
|
||||
},
|
||||
"career": {
|
||||
"name": "carreira",
|
||||
"description": "Carreira"
|
||||
},
|
||||
"custom": {
|
||||
"name": "personalizado",
|
||||
"description": "Intervalo personalizado",
|
||||
"options": {
|
||||
"start": {
|
||||
"name": "iniciar",
|
||||
"description": "Iniciar em número de dias atrás a partir de hoje"
|
||||
},
|
||||
"end": {
|
||||
"name": "terminar",
|
||||
"description": "Termina em número de dias atrás a partir de hoje"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"options": {
|
||||
"clan": {
|
||||
"name": "clã",
|
||||
"description": "O nome ou tag do clã"
|
||||
},
|
||||
"tank": {
|
||||
"name": "tanque",
|
||||
"description": "O tanque para obter estatísticas para"
|
||||
},
|
||||
"username": {
|
||||
"name": "nome de usuário",
|
||||
"description": "O nome de usuário Blitz do jogador"
|
||||
},
|
||||
"filters": {
|
||||
"nation": {
|
||||
"name": "nação",
|
||||
"description": "Nação"
|
||||
},
|
||||
"class": {
|
||||
"name": "classe",
|
||||
"description": "Classe"
|
||||
},
|
||||
"type": {
|
||||
"name": "tipo",
|
||||
"description": "Tipo"
|
||||
}
|
||||
},
|
||||
"region": {
|
||||
"name": "região",
|
||||
"description": "Região"
|
||||
},
|
||||
"tier": {
|
||||
"name": "nível",
|
||||
"description": "Nível",
|
||||
"choices": {
|
||||
"tier": "Tier {tier_1} - {tier_2}"
|
||||
}
|
||||
}
|
||||
},
|
||||
"periods": {
|
||||
"career": "Carreira",
|
||||
"today": "Hoje",
|
||||
"days": "{days} days",
|
||||
"custom": "{day_1} - {day_2} days"
|
||||
},
|
||||
"filters": {
|
||||
"none": "Sem filtros",
|
||||
"tier": "Tier {tier}"
|
||||
},
|
||||
"no_data": {
|
||||
"battles_in_period": "Não há batalhas jogadas neste período",
|
||||
"battles_in_season": "Não há batalhas jogadas nesta temporada",
|
||||
"players_in_period": "Nenhum jogador neste período",
|
||||
"tanks_found": "Nenhum tanque encontrado"
|
||||
},
|
||||
"buttons": {
|
||||
"refresh": "Atualizar"
|
||||
},
|
||||
"hero_stats": {
|
||||
"battles": "Batalhas",
|
||||
"winrate": "Taxa de vitória",
|
||||
"damage": "Dano",
|
||||
"damage_ratio": "Razão entre dano dado e recebido",
|
||||
"tier": "Nível",
|
||||
"survival": "Sobrevivência",
|
||||
"accuracy": "Precisão",
|
||||
"kills": "Abates"
|
||||
}
|
||||
},
|
||||
"commands": {
|
||||
"dead": "# Stat Commands Are Dead\n\nThe BlitzKit Discord bot used to use BlitzStars to fetch periodic statistics. BlitzStars has enabled aggressive Cloudflare protections; hence, disabling BlitzKit from using BlitzStar's API. This has impacted the following commands:\n\n- `/stats`\n- `/today`\n- `/breakdown`\n- `/evolution`\n- `/full-stats`\n\nPlease use [Aftermath](<https://amth.one/invite>) as an alternative which is completely independent of BlitzStars. BlitzKit-hosted stat commands will return in the near future.",
|
||||
"replay": {
|
||||
"name": "replay",
|
||||
"description": "Exibir resultados de replays",
|
||||
"options": {
|
||||
"file": {
|
||||
"name": "file",
|
||||
"description": "Replay file"
|
||||
}
|
||||
}
|
||||
},
|
||||
"research": {
|
||||
"name": "pesquisa",
|
||||
"description": "Liste as despesas na pesquisa de uma linha",
|
||||
"options": {
|
||||
"target_tank": {
|
||||
"name": "tanque-alvo",
|
||||
"description": "O último tanque para pesquisar na linha"
|
||||
},
|
||||
"starting_tank": {
|
||||
"name": "tanque-inicial",
|
||||
"description": "O tanque inicial na linha (inferido automaticamente se não fornecido)"
|
||||
}
|
||||
},
|
||||
"body": {
|
||||
"subtitle": "Pesquisa",
|
||||
"total": "Total",
|
||||
"research": "Research: {cost}",
|
||||
"upgrades": "Upgrades: {cost}",
|
||||
"purchase": "Purchase: {cost}",
|
||||
"equipment": "Equipment: {cost}",
|
||||
"estimation": "# Esta é uma estimativa!\n\nEsta lista pode incluir tanques já pesquisados devido à informação imprecisa que a Wargaming fornece. Tente fornecer um `tanque-inicial` da linha ao usar o comando, se puder."
|
||||
},
|
||||
"errors": {
|
||||
"non_tech_tree": "# {tank} is not on the tech tree\n\nYou cannot research a premium/collector tank.",
|
||||
"tier_1": "# {tank} is a tier I\n\nTier I tanks are always unlocked for free for all players.",
|
||||
"already_researched": "# {tank} is already researched\n\nTry providing a `starting-tank` when using the command to view the totals for a line you have already researched.",
|
||||
"start_end_equal": "# {tank} was provided twice\n\nMake sure `starting-tank` and `target-tank` are different.",
|
||||
"tanks_not_on_line": "# {tank_1} and {tank_2} are not on the same line\n\nMake sure `starting-tank` and `target-tank` are on the same tech-tree line.",
|
||||
"unordered": "# {tank_1} higher tiered to {tank_2}\n\nMake sure to provide {tank_2} as the `starting-tank` instead as it is the lower tiered tank."
|
||||
}
|
||||
},
|
||||
"about": {
|
||||
"name": "sobre",
|
||||
"description": "Todas as informações que você precisa sobre o bot",
|
||||
"subcommands": {
|
||||
"commands": {
|
||||
"name": "comandos",
|
||||
"description": "Lista de todos os comandos e suas descrições",
|
||||
"body": "# Comandos\n\nBlitzKit oferece os seguintes comandos:\n"
|
||||
},
|
||||
"embeds": {
|
||||
"name": "incorporar",
|
||||
"description": "Como incorporações funcionam"
|
||||
},
|
||||
"introduction": {
|
||||
"name": "Introdução",
|
||||
"description": "Sobre o bot"
|
||||
},
|
||||
"invite": {
|
||||
"name": "convite",
|
||||
"description": "Como convidar o bot"
|
||||
},
|
||||
"timezones": {
|
||||
"name": "fusos horários",
|
||||
"description": "Como o BlitzKit inferi e usa seu fuso horário"
|
||||
},
|
||||
"credits": {
|
||||
"name": "créditos",
|
||||
"description": "Pessoas que ajudaram BlitzKit"
|
||||
}
|
||||
}
|
||||
},
|
||||
"breakdown": {
|
||||
"name": "divisão",
|
||||
"description": "Análise de um período por tanques jogados",
|
||||
"body": {
|
||||
"total": "Total",
|
||||
"battles": "Batalhas",
|
||||
"wn8": "WN8",
|
||||
"winrate": "Taxa de vitória",
|
||||
"damage": "Dano",
|
||||
"unknown_tank": "Unknown tank {id}"
|
||||
}
|
||||
},
|
||||
"debug": {
|
||||
"name": "depuração",
|
||||
"description": "Depurar informações sobre o bot",
|
||||
"body": {
|
||||
"title": "# Depuração\n",
|
||||
"version": "Versão",
|
||||
"shard": {
|
||||
"label": "Fragmento",
|
||||
"default": "padrão"
|
||||
},
|
||||
"uptime": "Tempo de atividade"
|
||||
}
|
||||
},
|
||||
"evolution": {
|
||||
"name": "evolução",
|
||||
"description": "Evolução das estatísticas",
|
||||
"groups": {
|
||||
"player": {
|
||||
"name": "jogador",
|
||||
"description": "Estatísticas do Jogador"
|
||||
},
|
||||
"tank": {
|
||||
"name": "tanque",
|
||||
"description": "Estatísticas do tanque"
|
||||
}
|
||||
}
|
||||
},
|
||||
"inactive": {
|
||||
"name": "inativo",
|
||||
"description": "Liste todos os jogadores inativos em um clã acima de um limite",
|
||||
"options": {
|
||||
"threshold": {
|
||||
"name": "limite",
|
||||
"description": "The number of days inactive (default: {days} days)"
|
||||
}
|
||||
},
|
||||
"body": {
|
||||
"subtitle": "Inactive for {days}+ days",
|
||||
"listing": "{days} days"
|
||||
}
|
||||
},
|
||||
"full_stats": {
|
||||
"name": "estatísticas-completas",
|
||||
"description": "Estatísticas completas dentro do jogo",
|
||||
"body": {
|
||||
"cards": {
|
||||
"games": {
|
||||
"title": "Jogos",
|
||||
"winrate": "Taxa de vitória",
|
||||
"battles": "Batalhas",
|
||||
"wins_losses": "Vitórias / Derrotas"
|
||||
},
|
||||
"efficiency": {
|
||||
"title": "Eficiência",
|
||||
"wn8": "WN8",
|
||||
"survival": "Sobrevivência",
|
||||
"accuracy": "Precisão"
|
||||
},
|
||||
"lethality": {
|
||||
"title": "Letalidade",
|
||||
"average_damage": "Dano médio",
|
||||
"damage_per_tier": "Dano por nível",
|
||||
"damage_ratio": "Razão entre dano dado e recebido",
|
||||
"average_kills": "Média de abates"
|
||||
},
|
||||
"miscellaneous": {
|
||||
"title": "Diversos",
|
||||
"average_tier": "Nível médio",
|
||||
"average_spots": "Média de detecções",
|
||||
"average_xp": "EXP Médio",
|
||||
"kills_to_death_ratio": "Razão entre abates e mortes"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"link": {
|
||||
"name": "link",
|
||||
"description": "Conecte sua conta Blitz e Discord",
|
||||
"body": {
|
||||
"accounts_linked": "Contas vinculadas",
|
||||
"no_role_permissions": {
|
||||
"title": "{name} failed to verify",
|
||||
"description": "Eu não tenho permissão para gerenciar funções."
|
||||
}
|
||||
},
|
||||
"embed": {
|
||||
"title": "Conta incorreta?",
|
||||
"description": "Use o comando novamente e selecione um nome de usuário dos resultados da pesquisa."
|
||||
}
|
||||
},
|
||||
"search_clans": {
|
||||
"name": "procurar-clãs",
|
||||
"description": "Procurar clãs",
|
||||
"options": {
|
||||
"limit": {
|
||||
"name": "limite",
|
||||
"description": "The max number of clan results (default: {limit})"
|
||||
}
|
||||
},
|
||||
"body": {
|
||||
"title": "Clan search for {search} in region {region}",
|
||||
"no_results": "Nenhum clã encontrado"
|
||||
}
|
||||
},
|
||||
"search_players": {
|
||||
"name": "pesquisa-jogadores",
|
||||
"description": "Procurar jogadores",
|
||||
"options": {
|
||||
"limit": {
|
||||
"name": "limite",
|
||||
"description": "The max number of player results (default: {limit})"
|
||||
}
|
||||
},
|
||||
"body": {
|
||||
"title": "Player search for {search} in region {region}",
|
||||
"no_results": "Nenhum jogador encontrado"
|
||||
}
|
||||
},
|
||||
"rating_leaderboard": {
|
||||
"name": "classificação-tabela de classificação",
|
||||
"description": "Estatísticas de batalhas de classificação",
|
||||
"subcommands": {
|
||||
"neighbors": {
|
||||
"name": "vizinhos",
|
||||
"description": "Jogadores vizinhos na tabela de classificação"
|
||||
},
|
||||
"league": {
|
||||
"name": "Liga",
|
||||
"description": "Melhores jogadores de uma liga"
|
||||
}
|
||||
},
|
||||
"options": {
|
||||
"limit": {
|
||||
"name": "limite",
|
||||
"description": "How many neighbors to display (default: {count})"
|
||||
},
|
||||
"season": {
|
||||
"name": "temporada",
|
||||
"description": "Número da temporada (padrão: atual)",
|
||||
"choices": {
|
||||
"current": "{season} (current)"
|
||||
}
|
||||
},
|
||||
"league": {
|
||||
"name": "Liga",
|
||||
"description": "A liga para exibir"
|
||||
}
|
||||
},
|
||||
"body": {
|
||||
"top_players": "Top {count} players",
|
||||
"no_participation": "# {player} didn't play rating in season {season}\n\nThis player did not participate in this season or did not get past calibration.",
|
||||
"no_ongoing_season": "# Nenhuma temporada em andamento\n\nNão há uma temporada de classificação em execução no momento.",
|
||||
"deleted_player": "Deleted {id}",
|
||||
"neighbors": "Classificação de vizinhos",
|
||||
"more": "+ {count} more"
|
||||
}
|
||||
},
|
||||
"today": {
|
||||
"name": "hoje",
|
||||
"description": "Tanques jogados hoje e estatísticas"
|
||||
},
|
||||
"stats": {
|
||||
"name": "estatísticas",
|
||||
"description": "Estatísticas rápidas para um período"
|
||||
},
|
||||
"owned_tanks": {
|
||||
"name": "tanques-possuídos",
|
||||
"description": "Mostra todos os tanques possuídos em um nível",
|
||||
"body": {
|
||||
"title": "# {name}'s owned tier {tier} tanks\n\n"
|
||||
}
|
||||
},
|
||||
"permissions": {
|
||||
"name": "Permissões",
|
||||
"description": "Verifica se o bot tem as permissões necessárias para funcionar",
|
||||
"body": {
|
||||
"title": "# Permissions\n\n{body}",
|
||||
"view_channels": "Ver canais: necessário para encontrar a mensagem em que o botão atualizar foi usado",
|
||||
"read_message_history": "Histórico de mensagens lidas: necessário para encontrar a mensagem para atualizar",
|
||||
"attach_files": "Anexar arquivos: necessário para adicionar imagens a comandos baseados em imagens",
|
||||
"external_emojis": "Emojis externos: necessário para adicionar bandeiras nacionais e emojis de classe de tanque"
|
||||
}
|
||||
},
|
||||
"ping": {
|
||||
"name": "ping",
|
||||
"description": "Verifique se o bot está vivo.",
|
||||
"body": {
|
||||
"pong": "Pong 🏓",
|
||||
"pong_with_time": "Pong 🏓 - {time}ms"
|
||||
},
|
||||
"subcommands": {
|
||||
"blitzkit": {
|
||||
"name": "blitzkit",
|
||||
"description": "Ping BlitzKit"
|
||||
},
|
||||
"wotb": {
|
||||
"name": "wotb",
|
||||
"description": "Ping World of Tanks Blitz"
|
||||
}
|
||||
}
|
||||
},
|
||||
"player_info": {
|
||||
"name": "informação do jogador",
|
||||
"description": "Informações básicas sobre um jogador",
|
||||
"body": {
|
||||
"title": "{name}'s information",
|
||||
"nickname": "Apelido",
|
||||
"battles": "Batalhas",
|
||||
"winrate": "Taxa de vitória",
|
||||
"account_id": "ID da conta",
|
||||
"created": "Criado",
|
||||
"last_battle": "Última batalha"
|
||||
}
|
||||
},
|
||||
"rating": {
|
||||
"name": "classificação",
|
||||
"description": "Estatísticas de jogador de classificação",
|
||||
"subcommands": {
|
||||
"today": {
|
||||
"name": "hoje",
|
||||
"description": "Estatísticas de classificação hoje"
|
||||
},
|
||||
"season": {
|
||||
"name": "temporada",
|
||||
"description": "Estatísticas de classificação desta temporada"
|
||||
}
|
||||
},
|
||||
"body": {
|
||||
"subtitle": {
|
||||
"today": "Estatísticas de classificação hoje",
|
||||
"season": "Estatísticas de classificação desta temporada"
|
||||
}
|
||||
},
|
||||
"errors": {
|
||||
"no_participation": "# {name} hasn't played rating\n\nThis player hasn't participated in the rating gamemode this season.",
|
||||
"unrecorded_stats": "# Estatísticas atualmente indisponível\n\nWargaming pode estar no momento, enfrentando tempo de inatividade do servidor. Se houver uma temporada em curso, as estatísticas deverão ser disponibilizadas dentro de 24 horas."
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"website": {
|
||||
"redirect": {
|
||||
"title": "301: moved permanently",
|
||||
@@ -741,14 +281,6 @@
|
||||
}
|
||||
},
|
||||
"home": {
|
||||
"pwa": {
|
||||
"title": "Install the BlitzKit App",
|
||||
"new": "NEW",
|
||||
"checking": "Checking compatibility...",
|
||||
"instructions": "Instructions for Apple devices.",
|
||||
"install": "Install",
|
||||
"dismiss": "Dismiss"
|
||||
},
|
||||
"discord": {
|
||||
"join_short": "Join cool people!",
|
||||
"join_long": "Join super duper cool people!",
|
||||
|
||||
@@ -37,10 +37,11 @@
|
||||
"d_1": "Вчера"
|
||||
},
|
||||
"branches": {
|
||||
"local": "dev",
|
||||
"dev": "бета",
|
||||
"opentest": "общий тест",
|
||||
"preview": "превью"
|
||||
"beta": "Бета",
|
||||
"development": "Development",
|
||||
"opentest": "Открытый тест",
|
||||
"preview": "Preview",
|
||||
"production": "Production"
|
||||
},
|
||||
"locales": {
|
||||
"en": "Английский",
|
||||
@@ -184,467 +185,6 @@
|
||||
"cumulative_battle_life_time": "Общее время в боях"
|
||||
}
|
||||
},
|
||||
"bot": {
|
||||
"common": {
|
||||
"errors": {
|
||||
"clan_not_found": "# Не удалось найти клан\nНе найден «{search}». Попробуйте выбрать клан из результатов поиска.",
|
||||
"player_not_found": "# Не удалось найти пользователя\nНе удалось найти пользователя «{search}». Попробуйте выбрать пользователя из результатов поиска, введя правильное имя пользователя или используя команду «/link».",
|
||||
"player_not_linked": "# Используйте «/link», чтобы начать\nЯ не знаю, кто ты, но давай познакомимся сегодня!",
|
||||
"tank_name_not_found": "# Танк не найден\nНе удалось найти танк с названием «{search}».",
|
||||
"tank_id_not_found": "# Танк не найден\nНе удалось найти танк с ID «{search}». Попробуйте ввести название танка вместо числа.",
|
||||
"no_tank_stats": "# Статистика танка недоступна\nУ этого игрока нет доступной статистики. Возможно, это не тот игрок, которого вы ищете.",
|
||||
"get_help": "Получить помощь",
|
||||
"uncaught_error": "# BlitzKit столкнулся с ошибкой!\nНам очень жаль. Не стесняйтесь и [присоединяйтесь к официальному серверу Discord](https://discord.gg/nDt7AjGJQH), чтобы получить помощь.",
|
||||
"preview": "# Эта команда находится в тестируется\n\nВы можете получить доступ к этой команде только на [официальном сервере Discord] (https://discord.gg/nDt7AjGJQH). Команда скоро станет общедоступной.",
|
||||
"query_too_small": "# Ваш поисковой слишком короткий\nДлина вашего запроса не менее 3 символов.",
|
||||
"query_too_long": "# Ваш поисковой запрос слишком длинный\nДлина вашего запроса должна составлять не более 100 символов."
|
||||
},
|
||||
"wn8": {
|
||||
"name": "WN8",
|
||||
"types": {
|
||||
"very_bad": "Очень плохо",
|
||||
"bad": "Плохо",
|
||||
"below_average": "Ниже среднего",
|
||||
"average": "Средне",
|
||||
"above_average": "Выше среднего",
|
||||
"good": "Хорошо",
|
||||
"very_good": "Очень хорошо",
|
||||
"great": "Отлично",
|
||||
"unicum": "Уникально",
|
||||
"super_unicum": "Крайне уникально"
|
||||
}
|
||||
},
|
||||
"subcommands": {
|
||||
"today": {
|
||||
"name": "cегодня",
|
||||
"description": "Cегодня"
|
||||
},
|
||||
"30": {
|
||||
"name": "30",
|
||||
"description": "30 дней"
|
||||
},
|
||||
"60": {
|
||||
"name": "60",
|
||||
"description": "60 дней"
|
||||
},
|
||||
"90": {
|
||||
"name": "90",
|
||||
"description": "90 дней"
|
||||
},
|
||||
"career": {
|
||||
"name": "карьера",
|
||||
"description": "Карьера"
|
||||
},
|
||||
"custom": {
|
||||
"name": "пользовательский",
|
||||
"description": "Собственный диапазон",
|
||||
"options": {
|
||||
"start": {
|
||||
"name": "начать",
|
||||
"description": "Начать через N дней с сегодняшнего дня"
|
||||
},
|
||||
"end": {
|
||||
"name": "конец",
|
||||
"description": "Закончить через N дней с сегодняшнего дня"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"options": {
|
||||
"clan": {
|
||||
"name": "клан",
|
||||
"description": "Название или тег клана"
|
||||
},
|
||||
"tank": {
|
||||
"name": "танк",
|
||||
"description": "Танк для получения статистики для"
|
||||
},
|
||||
"username": {
|
||||
"name": "ник",
|
||||
"description": "Ник игрока в Blitz"
|
||||
},
|
||||
"filters": {
|
||||
"nation": {
|
||||
"name": "нация",
|
||||
"description": "Нация"
|
||||
},
|
||||
"class": {
|
||||
"name": "класс",
|
||||
"description": "Класс"
|
||||
},
|
||||
"type": {
|
||||
"name": "тип",
|
||||
"description": "Тип"
|
||||
}
|
||||
},
|
||||
"region": {
|
||||
"name": "регион",
|
||||
"description": "Регион"
|
||||
},
|
||||
"tier": {
|
||||
"name": "уровень",
|
||||
"description": "Уровень",
|
||||
"choices": {
|
||||
"tier": "Уровень {tier_1} - {tier_2}"
|
||||
}
|
||||
}
|
||||
},
|
||||
"periods": {
|
||||
"career": "Карьера",
|
||||
"today": "Cегодня",
|
||||
"days": "{days} дней",
|
||||
"custom": "{day_1} - {day_2} дней"
|
||||
},
|
||||
"filters": {
|
||||
"none": "Без фильтров",
|
||||
"tier": "{tier} уровень"
|
||||
},
|
||||
"no_data": {
|
||||
"battles_in_period": "За этот период боёв не было",
|
||||
"battles_in_season": "За этот сезон боёв не было",
|
||||
"players_in_period": "Нет игроков за этот период",
|
||||
"tanks_found": "Танки не найдены"
|
||||
},
|
||||
"buttons": {
|
||||
"refresh": "Обновить"
|
||||
},
|
||||
"hero_stats": {
|
||||
"battles": "Боёв",
|
||||
"winrate": "Коэффициент побед",
|
||||
"damage": "Урон",
|
||||
"damage_ratio": "Коэффициент урона",
|
||||
"tier": "Уровень",
|
||||
"survival": "Выживание",
|
||||
"accuracy": "Точность стрельбы",
|
||||
"kills": "Уничтожил"
|
||||
}
|
||||
},
|
||||
"commands": {
|
||||
"dead": "# Команды статистики мертвы\n\nБот BlitzKit использует BlitzStars для получения периодической статистики. BlitzStars включил агрессивную защиту Cloudflare; следовательно, отключив BlitzKit от использования API BlitzStar. Это повлияло на следующие команды:\n\n- `/stats`\n- `/today`\n- `/breakdown`\n- `/evolution`\n- `/full-stats`\n\nПожалуйста, используйте [Aftermath](<https://amth.one/invite>) в качестве альтернативы, которая совершенно не зависит от BlitzStars. Команда статистики BlitzKit-hosted вернется в ближайшее время.",
|
||||
"replay": {
|
||||
"name": "повтор",
|
||||
"description": "Показать результаты повтора",
|
||||
"options": {
|
||||
"file": {
|
||||
"name": "файл",
|
||||
"description": "Запись повтора"
|
||||
}
|
||||
}
|
||||
},
|
||||
"research": {
|
||||
"name": "исследование",
|
||||
"description": "Список ресурсов для исследования ветки",
|
||||
"options": {
|
||||
"target_tank": {
|
||||
"name": "желаемый танк",
|
||||
"description": "Желаемый танк ветки исследования"
|
||||
},
|
||||
"starting_tank": {
|
||||
"name": "стартовый-танк",
|
||||
"description": "Стартовый танк в ветке (назначен автоматически, если не установлен)"
|
||||
}
|
||||
},
|
||||
"body": {
|
||||
"subtitle": "Исследование",
|
||||
"total": "Всего",
|
||||
"research": "Исследование: {cost}",
|
||||
"upgrades": "Улучшения: {cost}",
|
||||
"purchase": "Покупка: {cost}",
|
||||
"equipment": "Снаряжение: {cost}",
|
||||
"estimation": "# Это приблизительная оценка!\n\nВ этот список могут входить уже исследованные танки из-за неточной информации, предоставляемой Wargaming. Попробуйте указать «стартовый танк» в строке при использовании команды, если сможете."
|
||||
},
|
||||
"errors": {
|
||||
"non_tech_tree": "# {tank} отсутствует в дереве танков\n\nВы не можете исследовать премиумный / коллекционный танк.",
|
||||
"tier_1": "# {tank} — танк I уровня\n\nУровень I всегда открыт бесплатно для всех игроков.",
|
||||
"already_researched": "# {tank} уже исследован\n\nПопробуйте предоставить «starting-tank» при использовании команды для просмотра итогов уже исследованной ветки.",
|
||||
"start_end_equal": "# {tank} был предоставлен дважды\n\nУбедитесь, что «starting-tank» и «target-tank» различаются.",
|
||||
"tanks_not_on_line": "# {tank_1} и {tank_2} находятся не в одной ветке\n\nУбедитесь, что «starting-tank» и «target-tank» находятся на той же ветке дерева танков.",
|
||||
"unordered": "# У {tank_1} более высокий уровень чем у {tank_2}\n\nОбязательно укажите {tank_2} в качестве «starting-tank», так как это танк более низкого уровня."
|
||||
}
|
||||
},
|
||||
"about": {
|
||||
"name": "about",
|
||||
"description": "Вся необходимая информация о боте",
|
||||
"subcommands": {
|
||||
"commands": {
|
||||
"name": "команды",
|
||||
"description": "Список всех команд и их описаний",
|
||||
"body": "# Команды\n\nBlitzKit предлагает следующие команды:\n\n"
|
||||
},
|
||||
"embeds": {
|
||||
"name": "embeds",
|
||||
"description": "Как работают встраиваемые элементы"
|
||||
},
|
||||
"introduction": {
|
||||
"name": "введение",
|
||||
"description": "О боте"
|
||||
},
|
||||
"invite": {
|
||||
"name": "пригласить",
|
||||
"description": "Как пригласить бота"
|
||||
},
|
||||
"timezones": {
|
||||
"name": "timezones",
|
||||
"description": "Как BlitzKit определяет и использует ваш часовой пояс"
|
||||
},
|
||||
"credits": {
|
||||
"name": "авторы",
|
||||
"description": "Люди, которые помогли BlitzKit"
|
||||
}
|
||||
}
|
||||
},
|
||||
"breakdown": {
|
||||
"name": "распределение",
|
||||
"description": "Статистика игр за период с распределением по танкам",
|
||||
"body": {
|
||||
"total": "Всего",
|
||||
"battles": "Боёв",
|
||||
"wn8": "WN8",
|
||||
"winrate": "Коэффициент побед",
|
||||
"damage": "Урон",
|
||||
"unknown_tank": "Неизвестный танк {id}"
|
||||
}
|
||||
},
|
||||
"debug": {
|
||||
"name": "отладка",
|
||||
"description": "Сведения для отладки",
|
||||
"body": {
|
||||
"title": "# Debug\n\n",
|
||||
"version": "Версия",
|
||||
"shard": {
|
||||
"label": "Фрагмент",
|
||||
"default": "default"
|
||||
},
|
||||
"uptime": "Время работы"
|
||||
}
|
||||
},
|
||||
"evolution": {
|
||||
"name": "изменения",
|
||||
"description": "Изменения статистики",
|
||||
"groups": {
|
||||
"player": {
|
||||
"name": "игрок",
|
||||
"description": "Статистика игрока"
|
||||
},
|
||||
"tank": {
|
||||
"name": "танк",
|
||||
"description": "Статистика танков"
|
||||
}
|
||||
}
|
||||
},
|
||||
"inactive": {
|
||||
"name": "неактивно",
|
||||
"description": "Список всех неактивных игроков в клане выше порога",
|
||||
"options": {
|
||||
"threshold": {
|
||||
"name": "порог",
|
||||
"description": "Количество дней не активности (по умолчанию: {days} дней)"
|
||||
}
|
||||
},
|
||||
"body": {
|
||||
"subtitle": "Неактивен {days}+ дней",
|
||||
"listing": "{days{days}"
|
||||
}
|
||||
},
|
||||
"full_stats": {
|
||||
"name": "full-stats",
|
||||
"description": "Полная игровая статистика",
|
||||
"body": {
|
||||
"cards": {
|
||||
"games": {
|
||||
"title": "Игры",
|
||||
"winrate": "Коэффициент побед",
|
||||
"battles": "Боёв",
|
||||
"wins_losses": "Побед / поражений"
|
||||
},
|
||||
"efficiency": {
|
||||
"title": "Эффективность",
|
||||
"wn8": "WN8",
|
||||
"survival": "Выжил",
|
||||
"accuracy": "Точность стрельбы"
|
||||
},
|
||||
"lethality": {
|
||||
"title": "Смертность",
|
||||
"average_damage": "Средний урон",
|
||||
"damage_per_tier": "Урон по уровню",
|
||||
"damage_ratio": "Коэффициент урона",
|
||||
"average_kills": "Среднее число уничтоженных"
|
||||
},
|
||||
"miscellaneous": {
|
||||
"title": "Прочее",
|
||||
"average_tier": "Средний уровень",
|
||||
"average_spots": "Среднее число попаданий",
|
||||
"average_xp": "Средний опыт",
|
||||
"kills_to_death_ratio": "Коэффициент убийств и смертей"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"link": {
|
||||
"name": "ссылка",
|
||||
"description": "Привяжите учётную запись Blitz и Discord",
|
||||
"body": {
|
||||
"accounts_linked": "Аккаунты привязаны",
|
||||
"no_role_permissions": {
|
||||
"title": "{name} не удалось проверить",
|
||||
"description": "У меня нет разрешения на управление ролями."
|
||||
}
|
||||
},
|
||||
"embed": {
|
||||
"title": "Неверный аккаунт?",
|
||||
"description": "Используйте команду снова и выберите имя пользователя из результатов поиска."
|
||||
}
|
||||
},
|
||||
"search_clans": {
|
||||
"name": "search-clans",
|
||||
"description": "Поиск кланов",
|
||||
"options": {
|
||||
"limit": {
|
||||
"name": "лимит",
|
||||
"description": "Максимальное количество результатов клана (по умолчанию: {limit})"
|
||||
}
|
||||
},
|
||||
"body": {
|
||||
"title": "Поиск клана {search} в регионе {region}",
|
||||
"no_results": "Кланов не найдено"
|
||||
}
|
||||
},
|
||||
"search_players": {
|
||||
"name": "search-players",
|
||||
"description": "Поиск игроков",
|
||||
"options": {
|
||||
"limit": {
|
||||
"name": "лимит",
|
||||
"description": "Максимальное число результатов игрока (по умолчанию: {limit})"
|
||||
}
|
||||
},
|
||||
"body": {
|
||||
"title": "Поиск игрока {search} в регионе {region}",
|
||||
"no_results": "Игроков не найдено"
|
||||
}
|
||||
},
|
||||
"rating_leaderboard": {
|
||||
"name": "rating-leaderboard",
|
||||
"description": "Статистика рейтингов боёв",
|
||||
"subcommands": {
|
||||
"neighbors": {
|
||||
"name": "ближайшие",
|
||||
"description": "Ближайшие игроки в таблице лидеров"
|
||||
},
|
||||
"league": {
|
||||
"name": "лига",
|
||||
"description": "Топ игроков лиги"
|
||||
}
|
||||
},
|
||||
"options": {
|
||||
"limit": {
|
||||
"name": "лимит",
|
||||
"description": "Количество отображаемых ближайших игроков (по умолчанию: {count})"
|
||||
},
|
||||
"season": {
|
||||
"name": "сезон",
|
||||
"description": "Номер сезона (по умолчанию: текущий)",
|
||||
"choices": {
|
||||
"current": "{season} (текущий)"
|
||||
}
|
||||
},
|
||||
"league": {
|
||||
"name": "лига",
|
||||
"description": "Отображаемая лига"
|
||||
}
|
||||
},
|
||||
"body": {
|
||||
"top_players": "Топ {count} игроков",
|
||||
"no_participation": "# {player} не играл в рейтинг в сезоне {season}\n\nЭтот игрок не участвовал в этом сезоне или не получил прошлую калибровку.",
|
||||
"no_ongoing_season": "# Нет текущего сезона\n\nВ данный момент нет рейтингового сезона.",
|
||||
"deleted_player": "Удаленный {id}",
|
||||
"neighbors": "Рейтинг ближайших игроков",
|
||||
"more": "+ ещё {count}"
|
||||
}
|
||||
},
|
||||
"today": {
|
||||
"name": "today",
|
||||
"description": "Танки, на которых сыграли сегодня и статистика"
|
||||
},
|
||||
"stats": {
|
||||
"name": "статистика",
|
||||
"description": "Быстрая статистика за период"
|
||||
},
|
||||
"owned_tanks": {
|
||||
"name": "cобственные-танки",
|
||||
"description": "Показывает все принадлежащие танки на уровне",
|
||||
"body": {
|
||||
"title": "# {name} принадлежат танки {tier} уровня\n\n"
|
||||
}
|
||||
},
|
||||
"permissions": {
|
||||
"name": "разрешения",
|
||||
"description": "Проверяет, есть ли у бота необходимые разрешения для работы",
|
||||
"body": {
|
||||
"title": "# Разрешения\n\n{body}",
|
||||
"view_channels": "Просмотр каналов: необходимо найти сообщение, на котором была использована кнопка обновления",
|
||||
"read_message_history": "Просмотр истории сообщений: необходимо найти сообщение для обновления",
|
||||
"attach_files": "Прикрепить файлы: необходимо для добавления изображений в команды на основе изображения",
|
||||
"external_emojis": "Внешние эмоции: необходимы для добавления национальных флагов и эмодзи класса танков"
|
||||
}
|
||||
},
|
||||
"ping": {
|
||||
"name": "пинг",
|
||||
"description": "Проверьте, что бот жив.",
|
||||
"body": {
|
||||
"pong": "Понг 🏓",
|
||||
"pong_with_time": "Понг 🏓 — {time}мс"
|
||||
},
|
||||
"subcommands": {
|
||||
"blitzkit": {
|
||||
"name": "blitzkit",
|
||||
"description": "Пинг BlitzKit"
|
||||
},
|
||||
"wotb": {
|
||||
"name": "wotb",
|
||||
"description": "Пинг World of Tanks Blitz"
|
||||
}
|
||||
}
|
||||
},
|
||||
"player_info": {
|
||||
"name": "player-ifor",
|
||||
"description": "Basic information about a player",
|
||||
"body": {
|
||||
"title": "Информация о {name}",
|
||||
"nickname": "Никнейм",
|
||||
"battles": "Боёв",
|
||||
"winrate": "Коэффициент побед",
|
||||
"account_id": "ID учётной записи",
|
||||
"created": "Создано",
|
||||
"last_battle": "Последний бой"
|
||||
}
|
||||
},
|
||||
"rating": {
|
||||
"name": "рейтинг",
|
||||
"description": "Статистика рейтинга игрока",
|
||||
"subcommands": {
|
||||
"today": {
|
||||
"name": "cегодня",
|
||||
"description": "Статистика рейтинга за сегодня"
|
||||
},
|
||||
"season": {
|
||||
"name": "сезон",
|
||||
"description": "Статистика рейтинга в этом сезоне"
|
||||
}
|
||||
},
|
||||
"body": {
|
||||
"subtitle": {
|
||||
"today": "Статистика рейтинга за сегодня",
|
||||
"season": "Статистика рейтинга в этом сезоне"
|
||||
}
|
||||
},
|
||||
"errors": {
|
||||
"no_participation": "# {name} не получил рейтинга\n\nЭтот игрок в этом сезоне не участвовал в рейтинговом режиме.",
|
||||
"unrecorded_stats": "# Статистика недоступна в настоящее время\n\nВ настоящее время Wargaming, возможно, сталкивается с простоями сервера. Если сезон продолжается, статистика должна быть доступна в течение 24 часов."
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"website": {
|
||||
"redirect": {
|
||||
"title": "301: перемещено навсегда",
|
||||
@@ -741,14 +281,6 @@
|
||||
}
|
||||
},
|
||||
"home": {
|
||||
"pwa": {
|
||||
"title": "Установите приложение BlitzKit",
|
||||
"new": "НОВИНКА",
|
||||
"checking": "Проверка совместимости...",
|
||||
"instructions": "Инструкция для устройств Apple.",
|
||||
"install": "Установка",
|
||||
"dismiss": "Отклонить"
|
||||
},
|
||||
"discord": {
|
||||
"join_short": "Присоединяйтесь к крутым ребятам!",
|
||||
"join_long": "Присоединяйся к супер-дупер крутым ребятам!",
|
||||
|
||||
+42
-510
@@ -37,10 +37,11 @@
|
||||
"d_1": "Вчора"
|
||||
},
|
||||
"branches": {
|
||||
"local": "розробник",
|
||||
"dev": "бета",
|
||||
"opentest": "відкритий тест",
|
||||
"preview": "попередній перегляд"
|
||||
"beta": "Beta",
|
||||
"development": "Development",
|
||||
"opentest": "Відкритий тест",
|
||||
"preview": "Preview",
|
||||
"production": "Production"
|
||||
},
|
||||
"locales": {
|
||||
"en": "Англійська",
|
||||
@@ -184,467 +185,6 @@
|
||||
"cumulative_battle_life_time": "Загальний час бою"
|
||||
}
|
||||
},
|
||||
"bot": {
|
||||
"common": {
|
||||
"errors": {
|
||||
"clan_not_found": "# Не вдалося знайти клан\nНе вдалося знайти \"{search}\". Спробуйте обрати клан з результату пошуку.",
|
||||
"player_not_found": "# Не вдалося знайти користувача\nНе вдалося знайти користувача \"{search}\". Спробуйте вибрати користувача із результатів пошуку, ввівши правильне ім'я користувача, або скористайтеся командою `/link`.",
|
||||
"player_not_linked": "# Використайте команду \"/link\" щоб почати\nЯ не знаю, хто ви, але ви можете сказати мені сьогодні!",
|
||||
"tank_name_not_found": "# Танк не знайдено\nНе вдалося знайти танк із назвою «{search}».",
|
||||
"tank_id_not_found": "# Танк не знайдено\nНе вдалося знайти танк з ID «{search}». Спробуйте ввести назву танка замість номера.",
|
||||
"no_tank_stats": "# Немає статистики для танка\nЦей гравець не має статистики.\nМожливо, це не той гравець, якого ви шукаєте.",
|
||||
"get_help": "Допомогти Discord серверу",
|
||||
"uncaught_error": "# Упс! BlitzKit зіткнувся з помилкою!\nНам дуже шкода. Можете попросити допомоги на [офіційному сервері Discord](https://discord.gg/nDt7AjGJQH).",
|
||||
"preview": "# Ця команда є в попередньому перегляді\n\nВи можете отримати доступ лише до цієї команди на [офіційному сервері Discord](https://discord.gg/nDt7AjGJQH). Команда в цілому буде доступна найближчим часом.",
|
||||
"query_too_small": "# Ваш пошук занадто короткий\nВаш пошук повинен бути щонайменше 3 символи.",
|
||||
"query_too_long": "# Ваш пошук занадто довгий\nВаш пошук повинен бути щонайбільше 100 символи."
|
||||
},
|
||||
"wn8": {
|
||||
"name": "WN8",
|
||||
"types": {
|
||||
"very_bad": "Дуже погано",
|
||||
"bad": "Погано",
|
||||
"below_average": "Нижче середнього",
|
||||
"average": "Середнє",
|
||||
"above_average": "Вище середнього",
|
||||
"good": "Добре",
|
||||
"very_good": "Дуже добре",
|
||||
"great": "Відмінно",
|
||||
"unicum": "Винятковий",
|
||||
"super_unicum": "Супер винятковий"
|
||||
}
|
||||
},
|
||||
"subcommands": {
|
||||
"today": {
|
||||
"name": "сьогодні",
|
||||
"description": "Сьогодні"
|
||||
},
|
||||
"30": {
|
||||
"name": "30",
|
||||
"description": "30 днів"
|
||||
},
|
||||
"60": {
|
||||
"name": "60",
|
||||
"description": "60 днів"
|
||||
},
|
||||
"90": {
|
||||
"name": "90",
|
||||
"description": "90 днів"
|
||||
},
|
||||
"career": {
|
||||
"name": "кар'єра",
|
||||
"description": "Кар'єра"
|
||||
},
|
||||
"custom": {
|
||||
"name": "користувацьке",
|
||||
"description": "Власний діапазон",
|
||||
"options": {
|
||||
"start": {
|
||||
"name": "почати",
|
||||
"description": "Початок за кількістю днів тому від сьогодні"
|
||||
},
|
||||
"end": {
|
||||
"name": "кінець",
|
||||
"description": "Кінець за кількістю днів тому від сьогодні"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"options": {
|
||||
"clan": {
|
||||
"name": "клан",
|
||||
"description": "Назва клану або тег"
|
||||
},
|
||||
"tank": {
|
||||
"name": "танк",
|
||||
"description": "Танк для якого треба отримати статистику"
|
||||
},
|
||||
"username": {
|
||||
"name": "ім'я користувача",
|
||||
"description": "Бліц ім'я гравця"
|
||||
},
|
||||
"filters": {
|
||||
"nation": {
|
||||
"name": "нація",
|
||||
"description": "Нація"
|
||||
},
|
||||
"class": {
|
||||
"name": "клас",
|
||||
"description": "Клас"
|
||||
},
|
||||
"type": {
|
||||
"name": "вид",
|
||||
"description": "Вид"
|
||||
}
|
||||
},
|
||||
"region": {
|
||||
"name": "регіон",
|
||||
"description": "Регіон"
|
||||
},
|
||||
"tier": {
|
||||
"name": "рівень",
|
||||
"description": "Рівень",
|
||||
"choices": {
|
||||
"tier": "Рівень {tier_1} - {tier_2}"
|
||||
}
|
||||
}
|
||||
},
|
||||
"periods": {
|
||||
"career": "Кар'єра",
|
||||
"today": "Сьогодні",
|
||||
"days": "{days} днів",
|
||||
"custom": "{day_1} - {day_2} днів"
|
||||
},
|
||||
"filters": {
|
||||
"none": "Немає фільтрів",
|
||||
"tier": "Рівень {tier}"
|
||||
},
|
||||
"no_data": {
|
||||
"battles_in_period": "За цей період боїв не було",
|
||||
"battles_in_season": "У цьому сезоні боїв не було",
|
||||
"players_in_period": "Немає гравців за цей період",
|
||||
"tanks_found": "Жодних танків не знайдено"
|
||||
},
|
||||
"buttons": {
|
||||
"refresh": "Оновити"
|
||||
},
|
||||
"hero_stats": {
|
||||
"battles": "Бої",
|
||||
"winrate": "Відсоток перемог",
|
||||
"damage": "Шкода",
|
||||
"damage_ratio": "Коефіцієнт шкоди",
|
||||
"tier": "Рівень",
|
||||
"survival": "Виживання",
|
||||
"accuracy": "Точність",
|
||||
"kills": "Знищено"
|
||||
}
|
||||
},
|
||||
"commands": {
|
||||
"dead": ".",
|
||||
"replay": {
|
||||
"name": "реплей",
|
||||
"description": "Показати результати реплею",
|
||||
"options": {
|
||||
"file": {
|
||||
"name": "",
|
||||
"description": "Replay filehttps://crowdin.com/editor/blitzkrieg/80/en-uk?view=side-by-side#9706"
|
||||
}
|
||||
}
|
||||
},
|
||||
"research": {
|
||||
"name": "дослідження",
|
||||
"description": "Показує витрати в дослідженні гілки",
|
||||
"options": {
|
||||
"target_tank": {
|
||||
"name": "цільовий танк",
|
||||
"description": "Останній танк для дослідження в гілці"
|
||||
},
|
||||
"starting_tank": {
|
||||
"name": "початковий танк",
|
||||
"description": "Початковий танк в гілці (виводиться автоматично, якщо не передбачено)"
|
||||
}
|
||||
},
|
||||
"body": {
|
||||
"subtitle": "Дослідження",
|
||||
"total": "Загалом",
|
||||
"research": "Дослідження: {cost}",
|
||||
"upgrades": "Прокачування: {cost}",
|
||||
"purchase": "Вартість: {cost}",
|
||||
"equipment": "Спорядження: {cost}",
|
||||
"estimation": "# Це оцінка!\n\nЦей список може включати вже досліджені танки через неточну інформацію для вантажу. Спробуйте використати \"початковий танк\" з рядка за допомогою команди."
|
||||
},
|
||||
"errors": {
|
||||
"non_tech_tree": "#{tank} відсутній в дереві дослідження\n\nВи не можете дослідити преміум/колеційний танк.",
|
||||
"tier_1": "#{tank} І рівня \n\nТанки І рівня завжди розблоковані для всіх гравців безкоштовно",
|
||||
"already_researched": "# {tank} вже було досліджено\n\nСпробуйте використати `початковий-танк` коли використовуєте команду для перегляду загальної гілки, яку ви вже дослідили",
|
||||
"start_end_equal": "#{tank} було введено двічі \n\nПереконайтесь що `початковий-танк` та `ціль-танк` різні",
|
||||
"tanks_not_on_line": "# {tank_1} та {tank_2} не в одній гілці\n\nПереконайтесь що `початковий-танк` та `ціль-танк` знаходяться в єдиній гілці дерева дослідження",
|
||||
"unordered": "# {tank_1} вище рівнем відносно {tank_2}\n\nОбов’язково вкажіть {tank_2} як `початковий-танк`, оскільки це танк нижчого рівня."
|
||||
}
|
||||
},
|
||||
"about": {
|
||||
"name": "про бота",
|
||||
"description": "Вся інформація про бота",
|
||||
"subcommands": {
|
||||
"commands": {
|
||||
"name": "команди",
|
||||
"description": "Список всіх команд та їх описів",
|
||||
"body": "# Команди\n\nBlitzKit пропонує наступні команди:\n\n"
|
||||
},
|
||||
"embeds": {
|
||||
"name": "вкладення",
|
||||
"description": "Як працюють вкладення"
|
||||
},
|
||||
"introduction": {
|
||||
"name": "ознайомлення",
|
||||
"description": "Про бота"
|
||||
},
|
||||
"invite": {
|
||||
"name": "запрошення",
|
||||
"description": "Як запросити бота"
|
||||
},
|
||||
"timezones": {
|
||||
"name": "часові пояси",
|
||||
"description": "Як BlitzKit отримує інформацію про час і використовує ваш часовий пояс"
|
||||
},
|
||||
"credits": {
|
||||
"name": "кредити",
|
||||
"description": "Люди, які допомогли BlitzKit"
|
||||
}
|
||||
}
|
||||
},
|
||||
"breakdown": {
|
||||
"name": "аналіз",
|
||||
"description": "Аналіз періоду за зіграними танками",
|
||||
"body": {
|
||||
"total": "Загалом",
|
||||
"battles": "Бої",
|
||||
"wn8": "WN8",
|
||||
"winrate": "Відсоток перемог",
|
||||
"damage": "Шкода",
|
||||
"unknown_tank": "Невідомий танк {id}"
|
||||
}
|
||||
},
|
||||
"debug": {
|
||||
"name": "налагодження",
|
||||
"description": "Інформація про налагодження бота",
|
||||
"body": {
|
||||
"title": "# Налагодження\n\n",
|
||||
"version": "Версія",
|
||||
"shard": {
|
||||
"label": "Уламок",
|
||||
"default": "за замовчуванням"
|
||||
},
|
||||
"uptime": "Час роботи"
|
||||
}
|
||||
},
|
||||
"evolution": {
|
||||
"name": "еволюція",
|
||||
"description": "Еволюція статистики",
|
||||
"groups": {
|
||||
"player": {
|
||||
"name": "гравець",
|
||||
"description": "Статистика гравця"
|
||||
},
|
||||
"tank": {
|
||||
"name": "танк",
|
||||
"description": "Статистика танків"
|
||||
}
|
||||
}
|
||||
},
|
||||
"inactive": {
|
||||
"name": "неактивний",
|
||||
"description": "Відображає всіх неактивних гравців у клані вище порогу",
|
||||
"options": {
|
||||
"threshold": {
|
||||
"name": "поріг",
|
||||
"description": "Кількість днів неактивності (за замовчуванням: {days} днів)"
|
||||
}
|
||||
},
|
||||
"body": {
|
||||
"subtitle": "Неактивний {days}+ днів",
|
||||
"listing": "{days} днів"
|
||||
}
|
||||
},
|
||||
"full_stats": {
|
||||
"name": "повна статистика",
|
||||
"description": "Повна ігрова статистика",
|
||||
"body": {
|
||||
"cards": {
|
||||
"games": {
|
||||
"title": "Ігри",
|
||||
"winrate": "Відсоток перемог",
|
||||
"battles": "Бої",
|
||||
"wins_losses": "Перемоги / поразки"
|
||||
},
|
||||
"efficiency": {
|
||||
"title": "Ефективність",
|
||||
"wn8": "WN8",
|
||||
"survival": "Виживання",
|
||||
"accuracy": "Точність"
|
||||
},
|
||||
"lethality": {
|
||||
"title": "Летальність",
|
||||
"average_damage": "Середня шкода",
|
||||
"damage_per_tier": "Шкода за рівень",
|
||||
"damage_ratio": "Коефіцієнт шкоди",
|
||||
"average_kills": "Середня кількість знищень"
|
||||
},
|
||||
"miscellaneous": {
|
||||
"title": "Різне",
|
||||
"average_tier": "Середній рівень",
|
||||
"average_spots": "Середній засвіт",
|
||||
"average_xp": "Середній досвід",
|
||||
"kills_to_death_ratio": "Співвідношення знищень до смертей"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"link": {
|
||||
"name": "посилання",
|
||||
"description": "Прив'язує ваш Blitz та Discord акаунт",
|
||||
"body": {
|
||||
"accounts_linked": "Прив'язані акаунти",
|
||||
"no_role_permissions": {
|
||||
"title": "{name} не вдалося перевірити",
|
||||
"description": "У мене немає дозволу керувати ролями."
|
||||
}
|
||||
},
|
||||
"embed": {
|
||||
"title": "Невірний обліковий запис?",
|
||||
"description": "Використайте команду ще раз і виберіть ім'я користувача з результатів пошуку."
|
||||
}
|
||||
},
|
||||
"search_clans": {
|
||||
"name": "пошук кланів",
|
||||
"description": "Пошук кланів",
|
||||
"options": {
|
||||
"limit": {
|
||||
"name": "ліміт",
|
||||
"description": "Максимальна кількість результатів клану (за замовчуванням: {limit})"
|
||||
}
|
||||
},
|
||||
"body": {
|
||||
"title": "Пошук клану для {search} в регіоні {region}",
|
||||
"no_results": "Жодного клану не знайдено"
|
||||
}
|
||||
},
|
||||
"search_players": {
|
||||
"name": "пошук гравців",
|
||||
"description": "Пошук гравців",
|
||||
"options": {
|
||||
"limit": {
|
||||
"name": "ліміт",
|
||||
"description": "Максимальна кількість результатів гравця (за замовчуванням: {limit})"
|
||||
}
|
||||
},
|
||||
"body": {
|
||||
"title": "Пошук гравця для {search} у регіоні {region}",
|
||||
"no_results": "Гравця не знайдено"
|
||||
}
|
||||
},
|
||||
"rating_leaderboard": {
|
||||
"name": "таблиця рейтингу",
|
||||
"description": "Статистика рейтингових боїв",
|
||||
"subcommands": {
|
||||
"neighbors": {
|
||||
"name": "сусіди",
|
||||
"description": "Сусідуючі гравці в лідерборді"
|
||||
},
|
||||
"league": {
|
||||
"name": "ліга",
|
||||
"description": "Найкращий гравець ліги"
|
||||
}
|
||||
},
|
||||
"options": {
|
||||
"limit": {
|
||||
"name": "ліміт",
|
||||
"description": "Скільки сусідів відобразити (за замовчуванням: {count})"
|
||||
},
|
||||
"season": {
|
||||
"name": "сезон",
|
||||
"description": "Базова інформація про гравця",
|
||||
"choices": {
|
||||
"current": "{season} (поточний)"
|
||||
}
|
||||
},
|
||||
"league": {
|
||||
"name": "ліга",
|
||||
"description": "Ліга для відображення"
|
||||
}
|
||||
},
|
||||
"body": {
|
||||
"top_players": "Топ {count} гравців",
|
||||
"no_participation": "# {player} не грав у рейтингу в сезоні {season}\n\nЦей гравець не брав участь у цьому сезоні або не проходив калібрування",
|
||||
"no_ongoing_season": "# Немає поточного сезону\n\nВ даний час немає сезону рейтингу.",
|
||||
"deleted_player": "",
|
||||
"neighbors": "Сусіди по рейтингу",
|
||||
"more": "+ {count} ще"
|
||||
}
|
||||
},
|
||||
"today": {
|
||||
"name": "сьогодні",
|
||||
"description": "Сьогодні зіграні танки та статистика"
|
||||
},
|
||||
"stats": {
|
||||
"name": "статистика",
|
||||
"description": "Коротка статистика за період"
|
||||
},
|
||||
"owned_tanks": {
|
||||
"name": "отримані танки",
|
||||
"description": "Показує всі ваші танки даного рівня",
|
||||
"body": {
|
||||
"title": "# {name} отриманих рівнів {tier} танків\n\n"
|
||||
}
|
||||
},
|
||||
"permissions": {
|
||||
"name": "дозволи",
|
||||
"description": "Перевіряє чи бот має необхідні дозволи для роботи",
|
||||
"body": {
|
||||
"title": "# Дозволи\n\n{body}",
|
||||
"view_channels": "Перегляньте канали: необхідне для знаходження повідомлення, на якому використовувалася кнопка оновлення",
|
||||
"read_message_history": "Прочитайте історію повідомлень: потрібно знайти повідомлення для оновлення",
|
||||
"attach_files": "Закріпіть файли: потрібно для додавання зображень до команд на основі зображень",
|
||||
"external_emojis": "Зовнішні емодзі: потрібні для додавання емодзі національних прапорів та класів техніки"
|
||||
}
|
||||
},
|
||||
"ping": {
|
||||
"name": "",
|
||||
"description": "Перевірити чи бот живий",
|
||||
"body": {
|
||||
"pong": "Понг🏓",
|
||||
"pong_with_time": "Понг🏓 - {time}мс"
|
||||
},
|
||||
"subcommands": {
|
||||
"blitzkit": {
|
||||
"name": "BlitzKit",
|
||||
"description": "Ping BlitzKit"
|
||||
},
|
||||
"wotb": {
|
||||
"name": "WoTB",
|
||||
"description": "Ping World of Tanks Blitz"
|
||||
}
|
||||
}
|
||||
},
|
||||
"player_info": {
|
||||
"name": "інформація про гравця",
|
||||
"description": "Базова інформація про гравця",
|
||||
"body": {
|
||||
"title": "інформація про {name}",
|
||||
"nickname": "Нік",
|
||||
"battles": "Бої",
|
||||
"winrate": "Відсоток перемог",
|
||||
"account_id": "ID акаунта",
|
||||
"created": "Створено",
|
||||
"last_battle": "Остання битва"
|
||||
}
|
||||
},
|
||||
"rating": {
|
||||
"name": "рейтинг",
|
||||
"description": "Статистика рейтингових боїв гравця ",
|
||||
"subcommands": {
|
||||
"today": {
|
||||
"name": "сьогодні",
|
||||
"description": "Сьогоднішня статистика рейтингових боїв"
|
||||
},
|
||||
"season": {
|
||||
"name": "сезон",
|
||||
"description": "Статистика рейтингових боїв поточного сезону"
|
||||
}
|
||||
},
|
||||
"body": {
|
||||
"subtitle": {
|
||||
"today": "Сьогоднішня статистика рейтингових боїв",
|
||||
"season": "Статистика рейтингових боїв даного сезону"
|
||||
}
|
||||
},
|
||||
"errors": {
|
||||
"no_participation": "# {name} не грав рейтингові бої\n\nЦей гравець не брав участь у рейтинговому режимі цього сезону.",
|
||||
"unrecorded_stats": "# Статистика на цей момент недоступна\n\nWargaming наразі зіткнулась з технічними несправностями. Якщо зараз проходить сезон, статистика буде доступною в найближчі 24 години."
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"website": {
|
||||
"redirect": {
|
||||
"title": "301: переміщено назавжди",
|
||||
@@ -741,30 +281,22 @@
|
||||
}
|
||||
},
|
||||
"home": {
|
||||
"pwa": {
|
||||
"title": "",
|
||||
"new": "",
|
||||
"checking": "",
|
||||
"instructions": ".",
|
||||
"install": "",
|
||||
"dismiss": "Dismiss"
|
||||
},
|
||||
"discord": {
|
||||
"join_short": "Join cool people!",
|
||||
"join_long": "Join super duper cool people!",
|
||||
"join_short": "Приєднуйся до суспільства!",
|
||||
"join_long": "Приєднуйся до найкрутішого суспільства!",
|
||||
"action": "Discord"
|
||||
},
|
||||
"hero": {
|
||||
"credit": "By {name} ❤️"
|
||||
"credit": "Від {name} ❤️"
|
||||
},
|
||||
"hot_tanks": {
|
||||
"title": "Популярні танки",
|
||||
"subtitle": "Last {days} days"
|
||||
"subtitle": "Останні {days} днів"
|
||||
},
|
||||
"other_projects": {
|
||||
"title": "Інші класні проєкти"
|
||||
},
|
||||
"help_translate": "Please help translate {name} to {language}!",
|
||||
"help_translate": "Будь ласка, допоможіть перекласти {name} на {language}!",
|
||||
"seo_description": "Інструменти для всього, пов'язаного з WoT Blitz"
|
||||
},
|
||||
"docs": {
|
||||
@@ -778,7 +310,7 @@
|
||||
"reset": "Скинути",
|
||||
"shuffle": "Перемішати",
|
||||
"remove": "Видалити зіграні",
|
||||
"tracking": "BlitzKit is tracking your battles",
|
||||
"tracking": "BlitzKit відстежує ваші бої",
|
||||
"sort": {
|
||||
"button": "Сортувати за",
|
||||
"last_played": "Остання гра",
|
||||
@@ -804,15 +336,15 @@
|
||||
"description": "Tank playlist generator",
|
||||
"seo_description": "Don't know what to play in World of Tanks Blitz? Use BlitzKit Playlist to get suggestions!",
|
||||
"button": "Створити",
|
||||
"pool_size": "{count} possible tanks"
|
||||
"pool_size": "{count} можливі танки"
|
||||
},
|
||||
"mixer": {
|
||||
"name": "Mixer",
|
||||
"button": "Mix and match",
|
||||
"description": "Mix tank modules",
|
||||
"seo_description": "Mix and match hulls, turrets, and guns of tanks in World of Tanks Blitz",
|
||||
"screenshot": "Screenshot",
|
||||
"randomize": "Randomize"
|
||||
"screenshot": "Знімок екрану",
|
||||
"randomize": "Рандомізувати"
|
||||
},
|
||||
"guess": {
|
||||
"name": "Guess",
|
||||
@@ -821,9 +353,9 @@
|
||||
"seo_description": "Play a tank guessing game with a silhouette in World of Tanks Blitz",
|
||||
"search": {
|
||||
"placeholder": "Type to guess...",
|
||||
"skip": "Skip",
|
||||
"skip": "Пропустити",
|
||||
"guess": "Guess",
|
||||
"next": "Next",
|
||||
"next": "Наступний",
|
||||
"no_results": "Немає результатів"
|
||||
},
|
||||
"stats": "{correct} / {total} correct, {streak} streak",
|
||||
@@ -838,7 +370,7 @@
|
||||
"tier": "Рівень {tier}"
|
||||
},
|
||||
"tankopedia": {
|
||||
"search": "Search a stat...",
|
||||
"search": "Шукаємо стати...",
|
||||
"name": "Танкопедія",
|
||||
"button": "Знайти танки",
|
||||
"description": "Танкова енциклопедія",
|
||||
@@ -909,7 +441,7 @@
|
||||
"ricochet": "Рикошет",
|
||||
"explosion_radius": "Радіус розльоту уламків",
|
||||
"exit": "Вийти",
|
||||
"reset": "Reset"
|
||||
"reset": "Скинути"
|
||||
},
|
||||
"advanced": "Advanced highlighting",
|
||||
"shot_card": {
|
||||
@@ -918,7 +450,7 @@
|
||||
"spaced": "Spaced",
|
||||
"external": "External",
|
||||
"gap": "Gap",
|
||||
"gun": "Gun",
|
||||
"gun": "Пушка",
|
||||
"track": "Гусениці"
|
||||
},
|
||||
"status": {
|
||||
@@ -928,7 +460,7 @@
|
||||
"splash": "{damage} Од"
|
||||
},
|
||||
"stats": {
|
||||
"thickness_and_angle": "{thickness}mm {angle}°",
|
||||
"thickness_and_angle": "{thickness}мм {angle}°",
|
||||
"nominal": "{thickness}mm nominal",
|
||||
"ricochet_loss": "{loss}% penetration"
|
||||
}
|
||||
@@ -941,7 +473,7 @@
|
||||
"external": "External",
|
||||
"edit": {
|
||||
"label": "Редагувати",
|
||||
"reset": "Reset"
|
||||
"reset": "Скинути"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -954,7 +486,7 @@
|
||||
},
|
||||
"vanilla": "Vanilla",
|
||||
"opentest": "Відкритий тест",
|
||||
"full_name": "Full name",
|
||||
"full_name": "Повна назва",
|
||||
"nation": "Нація",
|
||||
"class": "Клас",
|
||||
"tier": "Рівень",
|
||||
@@ -1086,7 +618,7 @@
|
||||
"hullTraverseHardTerrain": "Hard",
|
||||
"hullTraverseMediumTerrain": "Середній",
|
||||
"hullTraverseSoftTerrain": "Soft",
|
||||
"health": "Health",
|
||||
"health": "Здоров'я",
|
||||
"fireChance": "Fire chance",
|
||||
"viewRange": "View range",
|
||||
"camouflageStill": "Нерухомо",
|
||||
@@ -1211,10 +743,10 @@
|
||||
"name": "Gallery",
|
||||
"button": "Browse all",
|
||||
"description": "Blitz player avatars",
|
||||
"seo_description": "All World of Tanks Blitz player avatars",
|
||||
"seo_description": "Усі World of Tanks Blitz аватари гравців",
|
||||
"last_updated": "Last updated on {time}",
|
||||
"search": {
|
||||
"hint": "Search avatars...",
|
||||
"hint": "Шукаємо аватари...",
|
||||
"results": "{count} avatars"
|
||||
}
|
||||
},
|
||||
@@ -1251,18 +783,18 @@
|
||||
}
|
||||
},
|
||||
"tier_list": {
|
||||
"name": "Tier list",
|
||||
"button": "Rank tanks",
|
||||
"description": "Rank Blitz tanks",
|
||||
"name": "Список рівнів",
|
||||
"button": "Ранги танків",
|
||||
"description": "Ранги танків з блітзу",
|
||||
"seo_description": "Explore tier lists ranking tanks from best to worst, based on player ratings and statistical performance in World of Tanks Blitz",
|
||||
"buttons": {
|
||||
"reset": "Reset",
|
||||
"share": "Share"
|
||||
"reset": "Скинути",
|
||||
"share": "Поділитися"
|
||||
}
|
||||
},
|
||||
"embed": {
|
||||
"name": "Embed",
|
||||
"button": "Create now",
|
||||
"button": "Створити зараз",
|
||||
"description": "Embeds for streaming",
|
||||
"seo_description": "Create embeds for streaming World of Tanks Blitz with extreme customization",
|
||||
"coming_soon": "More embeds coming soon.",
|
||||
@@ -1273,20 +805,20 @@
|
||||
},
|
||||
"configuration": {
|
||||
"import": {
|
||||
"title": "Import",
|
||||
"title": "Імпортувати",
|
||||
"description": "Paste your current URL if you have one already to import your settings",
|
||||
"hint": "Paste URL...",
|
||||
"hint": "Вставити посилання...",
|
||||
"apply": "Apply",
|
||||
"idiot_title": "Invalid URL",
|
||||
"idiot_title": "Некоректне посилання",
|
||||
"idiot_description": "Try pasting the URL that BlitzKit previously generated, you silly goose!",
|
||||
"idiot_button": "Okay, my bad"
|
||||
},
|
||||
"export": {
|
||||
"title": "Export",
|
||||
"title": "Експортувати",
|
||||
"description": "Copy all properties for you streaming software",
|
||||
"generate": {
|
||||
"button": "Generate URL",
|
||||
"title": "Generate URL",
|
||||
"button": "Згенерувати посилання",
|
||||
"title": "Генерація посилання",
|
||||
"subtitle": "Search an account to track",
|
||||
"cancel": "",
|
||||
"success": {
|
||||
@@ -1303,7 +835,7 @@
|
||||
},
|
||||
"customize": {
|
||||
"title": "Customize",
|
||||
"reset": "Reset",
|
||||
"reset": "Скинути",
|
||||
"description": "Bells and whistles of your embed"
|
||||
}
|
||||
},
|
||||
@@ -1351,14 +883,14 @@
|
||||
"seo_description": "Live and archived full rating leaderboard for World of Tanks Blitz"
|
||||
},
|
||||
"discord": {
|
||||
"name": "Discord bot",
|
||||
"button": "Install now",
|
||||
"name": "Діскорд бот",
|
||||
"button": "Встановити зараз",
|
||||
"description": "Stats right in Discord",
|
||||
"seo_description": "Get stats right in Discord with BlitzKit's Discord bot"
|
||||
},
|
||||
"more": {
|
||||
"name": "More coming soon",
|
||||
"button": "Join Discord",
|
||||
"name": "Буде через певний час",
|
||||
"button": "Приєднатись до Діскорду",
|
||||
"description": "What we're making",
|
||||
"seo_description": "What we're making with BlitzKit"
|
||||
},
|
||||
|
||||
+28
-496
@@ -13,18 +13,18 @@
|
||||
"hp": "{value} 生命值",
|
||||
"x": "x{value}",
|
||||
"percentage": "{value}%",
|
||||
"deg_s": "{value}度°/秒",
|
||||
"deg_s": "{value}度每秒",
|
||||
"plus": "+{value}"
|
||||
},
|
||||
"gun_types": {
|
||||
"auto_loader": "弹夹型坦克",
|
||||
"auto_reloader": "自动装填型坦克",
|
||||
"auto_reloader": "弹鼓型坦克",
|
||||
"regular": "单发"
|
||||
},
|
||||
"shells": {
|
||||
"ap": "穿甲弹",
|
||||
"ap_cr": "硬式复合穿甲弹",
|
||||
"hc": "反战车高爆弹",
|
||||
"hc": "破甲弹",
|
||||
"he": "高爆弹"
|
||||
},
|
||||
"player_count_period": {
|
||||
@@ -37,10 +37,11 @@
|
||||
"d_1": "昨日"
|
||||
},
|
||||
"branches": {
|
||||
"local": "开发者",
|
||||
"dev": "测试版",
|
||||
"beta": "测试版",
|
||||
"development": "Development",
|
||||
"opentest": "开放测试",
|
||||
"preview": "预览"
|
||||
"preview": "Preview",
|
||||
"production": "Production"
|
||||
},
|
||||
"locales": {
|
||||
"en": "英语",
|
||||
@@ -60,23 +61,23 @@
|
||||
"3": "平均",
|
||||
"4": "高于平均",
|
||||
"5": "好",
|
||||
"6": "非常好",
|
||||
"6": "好",
|
||||
"7": "很好",
|
||||
"8": "极品",
|
||||
"9": "超级强势玩家"
|
||||
"8": "非常好",
|
||||
"9": "极品"
|
||||
},
|
||||
"bkni_percentile": {
|
||||
"0": "Super malum",
|
||||
"1": "Malum",
|
||||
"2": "非常差",
|
||||
"0": "垃圾",
|
||||
"1": "非常差",
|
||||
"2": "很差",
|
||||
"3": "差",
|
||||
"4": "低于平均",
|
||||
"5": "平均",
|
||||
"6": "高于平均",
|
||||
"6": "较好",
|
||||
"7": "好",
|
||||
"8": "非常好",
|
||||
"9": "極品",
|
||||
"10": "超级强势玩家"
|
||||
"8": "很好",
|
||||
"9": "非常好",
|
||||
"10": "极品"
|
||||
},
|
||||
"nations": {
|
||||
"ussr": "苏联",
|
||||
@@ -101,7 +102,7 @@
|
||||
"other": "X系"
|
||||
},
|
||||
"tank_class_short": {
|
||||
"-1": "未识别",
|
||||
"-1": "未知",
|
||||
"0": "轻型坦克",
|
||||
"1": "中型坦克",
|
||||
"2": "重型战车",
|
||||
@@ -114,14 +115,14 @@
|
||||
"3": "坦克歼击车"
|
||||
},
|
||||
"tank_class_medium": {
|
||||
"-1": "未识别",
|
||||
"-1": "未知",
|
||||
"0": "轻型坦克",
|
||||
"1": "中型坦克",
|
||||
"2": "重型坦克",
|
||||
"3": "坦克歼击车"
|
||||
},
|
||||
"tree_type": {
|
||||
"-1": "未识别",
|
||||
"-1": "未知",
|
||||
"0": "科技树",
|
||||
"1": "金币车",
|
||||
"2": "收藏车"
|
||||
@@ -156,7 +157,7 @@
|
||||
"normalized_shots": "开火次数",
|
||||
"normalized_spotted": "侦查次数",
|
||||
"normalized_survived_battles": "存活率",
|
||||
"normalized_win_and_survived": "存活胜利率",
|
||||
"normalized_win_and_survived": "胜利并幸存的概率",
|
||||
"normalized_wins": "胜率",
|
||||
"normalized_xp": "经验值",
|
||||
"normalized_battle_life_time": "战斗时间",
|
||||
@@ -184,467 +185,6 @@
|
||||
"cumulative_battle_life_time": "总战斗时间"
|
||||
}
|
||||
},
|
||||
"bot": {
|
||||
"common": {
|
||||
"errors": {
|
||||
"clan_not_found": "# 找不到公会\n找不到\"{search}\"。请尝试从搜索结果中选择一个公会。",
|
||||
"player_not_found": "# 找不到玩家\n无法找到玩家 “{search}”。 尝试从搜索结果中选择玩家,或输入一个有效的玩家名称, 或使用“/link”命令。",
|
||||
"player_not_linked": "# 使用 `/link` 来开始\n我不知道你是谁,但你今天可以告诉我!",
|
||||
"tank_name_not_found": "# 找不到坦克\n找不到名为 “{search}” 的坦克。",
|
||||
"tank_id_not_found": "# 找不到坦克\n无法找到ID为 “{search}” 的坦克。 请尝试输入坦克的名称而不是数字。",
|
||||
"no_tank_stats": "# 没有这辆战车的数据\n这个玩家没有可用资料。 这可能不是你要找的玩家。",
|
||||
"get_help": "Discord的协助服务器",
|
||||
"uncaught_error": "# BlitzKit 发生错误!\n我们对此感到抱歉。 欢迎加入[官方Discord](https://discord.gg/nDt7AjGJQH),以方便帮助你解决问题。",
|
||||
"preview": "# 此命令处于预览\n\n您只能在[官方Discord服务器](https://discord.gg/nDt7AjGJQH)访问此命令。该命令将很快可用。",
|
||||
"query_too_small": "# 搜寻内容过短\n您的搜寻必需至少包含 3 个字元。",
|
||||
"query_too_long": "# 搜索内容过长\n您搜索的内容必须少于 100 个字符。"
|
||||
},
|
||||
"wn8": {
|
||||
"name": "WN8",
|
||||
"types": {
|
||||
"very_bad": "非常差",
|
||||
"bad": "差",
|
||||
"below_average": "低于平均",
|
||||
"average": "平均",
|
||||
"above_average": "高于平均",
|
||||
"good": "好",
|
||||
"very_good": "非常好",
|
||||
"great": "很好",
|
||||
"unicum": "极品",
|
||||
"super_unicum": "超强势玩家"
|
||||
}
|
||||
},
|
||||
"subcommands": {
|
||||
"today": {
|
||||
"name": "今日",
|
||||
"description": "今日:"
|
||||
},
|
||||
"30": {
|
||||
"name": "30",
|
||||
"description": "30 天"
|
||||
},
|
||||
"60": {
|
||||
"name": "60",
|
||||
"description": "60 天"
|
||||
},
|
||||
"90": {
|
||||
"name": "90",
|
||||
"description": "90 天"
|
||||
},
|
||||
"career": {
|
||||
"name": "生涯",
|
||||
"description": "玩家资料"
|
||||
},
|
||||
"custom": {
|
||||
"name": "自定义",
|
||||
"description": "自定义范围",
|
||||
"options": {
|
||||
"start": {
|
||||
"name": "开始",
|
||||
"description": "距今若干天前开始"
|
||||
},
|
||||
"end": {
|
||||
"name": "结束",
|
||||
"description": "距今若干天前开结束"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"options": {
|
||||
"clan": {
|
||||
"name": "公会",
|
||||
"description": "公会名称或标签"
|
||||
},
|
||||
"tank": {
|
||||
"name": "坦克",
|
||||
"description": "要获取战绩的坦克"
|
||||
},
|
||||
"username": {
|
||||
"name": "用户名",
|
||||
"description": "玩家的闪击战游戏昵称"
|
||||
},
|
||||
"filters": {
|
||||
"nation": {
|
||||
"name": "国别",
|
||||
"description": "国别"
|
||||
},
|
||||
"class": {
|
||||
"name": "坦克车型",
|
||||
"description": "坦克车型"
|
||||
},
|
||||
"type": {
|
||||
"name": "战车类型",
|
||||
"description": "战车类型"
|
||||
}
|
||||
},
|
||||
"region": {
|
||||
"name": "所在地区",
|
||||
"description": "地区"
|
||||
},
|
||||
"tier": {
|
||||
"name": "阶级",
|
||||
"description": "阶级",
|
||||
"choices": {
|
||||
"tier": "{tier_1} - {tier_2} 阶"
|
||||
}
|
||||
}
|
||||
},
|
||||
"periods": {
|
||||
"career": "玩家资料",
|
||||
"today": "今日:",
|
||||
"days": "{days} 天",
|
||||
"custom": "{day_1} - {day_2} 天"
|
||||
},
|
||||
"filters": {
|
||||
"none": "无筛选器",
|
||||
"tier": "{tier} 阶"
|
||||
},
|
||||
"no_data": {
|
||||
"battles_in_period": "在这段时间里没有参与任何战斗",
|
||||
"battles_in_season": "在这个赛季中没有战斗记录",
|
||||
"players_in_period": "这段时间内没有玩家",
|
||||
"tanks_found": "找不到战车"
|
||||
},
|
||||
"buttons": {
|
||||
"refresh": "刷新"
|
||||
},
|
||||
"hero_stats": {
|
||||
"battles": "战斗场次",
|
||||
"winrate": "胜率",
|
||||
"damage": "伤害",
|
||||
"damage_ratio": "伤害比",
|
||||
"tier": "阶级",
|
||||
"survival": "生存",
|
||||
"accuracy": "命中率",
|
||||
"kills": "击杀数"
|
||||
}
|
||||
},
|
||||
"commands": {
|
||||
"dead": "# 统计指令现已停用\nBlitzKit Discord 机器人此前依赖 BlitzStars 获取周期性的统计数据。由于 BlitzStars 已启用严格的 Cloudflare 防护,导致 BlitzKit 无法继续使用其 API。这已导致以下指令失效:\n/统计\n/今日\n/损坏\n/演变\n/完整统计\n请使用 [Aftermath](<https://amth.one/invite>) \n作为完全独立于 BlitzStars 的替代方案。由 BlitzKit 托管的统计指令将在近期内恢复。",
|
||||
"replay": {
|
||||
"name": "回放",
|
||||
"description": "显示重播结果",
|
||||
"options": {
|
||||
"file": {
|
||||
"name": "file",
|
||||
"description": "Replay file"
|
||||
}
|
||||
}
|
||||
},
|
||||
"research": {
|
||||
"name": "研发",
|
||||
"description": "列出研发线路的费用",
|
||||
"options": {
|
||||
"target_tank": {
|
||||
"name": "目标战车",
|
||||
"description": "需要研发的目标(战车)"
|
||||
},
|
||||
"starting_tank": {
|
||||
"name": "起始战车",
|
||||
"description": "研发线路中的起始战车(如果未提供则自动推定)"
|
||||
}
|
||||
},
|
||||
"body": {
|
||||
"subtitle": "研发",
|
||||
"total": "全部",
|
||||
"research": "研发:{cost}",
|
||||
"upgrades": "升级:{cost}",
|
||||
"purchase": "购买:{cost}",
|
||||
"equipment": "装备:{cost}",
|
||||
"estimation": "# 这是一个估计值!\n\n这个列表可能包含已经研发过的战车,因为 Wargaming 提供了不正确的资料。 如果可以,请尝试在同一研发线路中提供一个 “起始战车” 。"
|
||||
},
|
||||
"errors": {
|
||||
"non_tech_tree": "# \"{tank}\" 不在科技树里\n\n你不能研发一个 加值/收藏家 坦克。",
|
||||
"tier_1": "# {tank} 是一级坦克\n\n一级坦克一直是对所有玩家免费解锁的。",
|
||||
"already_researched": "# \"{tank}\" 已完成研发\n\n请尝试在同一研发线路上提供“起始坦克”, 以查看全部您已研发过的坦克。",
|
||||
"start_end_equal": "# \"{tank}\" 重复提供了\n\n请确认 \"初始坦克\" 和 \"目标坦克\" 是不同的。",
|
||||
"tanks_not_on_line": "# “{tank_1}” 和 “{tank_2}” 不在同一个研发线路上\n\n请确认“起始坦克” 和 “目标坦克” 在同一研发线路中。",
|
||||
"unordered": "# “{tank_1}” 阶级比 “{tank_2}” 高\n\n请以提供 {tank_2} 作为起始坦克,因为它的阶级更低。"
|
||||
}
|
||||
},
|
||||
"about": {
|
||||
"name": "关于",
|
||||
"description": "查看关于机器人的所有信息",
|
||||
"subcommands": {
|
||||
"commands": {
|
||||
"name": "指令",
|
||||
"description": "所有指令及其描述",
|
||||
"body": "# 指令\n\nBlitzKit 提供了以下指令:\n\n"
|
||||
},
|
||||
"embeds": {
|
||||
"name": "嵌入",
|
||||
"description": "嵌入如何运作"
|
||||
},
|
||||
"introduction": {
|
||||
"name": "介绍",
|
||||
"description": "关于此机器人"
|
||||
},
|
||||
"invite": {
|
||||
"name": "邀请",
|
||||
"description": "如何邀请机器人"
|
||||
},
|
||||
"timezones": {
|
||||
"name": "时区",
|
||||
"description": "BlitzKit 如何判断并使用你的时区"
|
||||
},
|
||||
"credits": {
|
||||
"name": "积分",
|
||||
"description": "谁帮助过 BlitzKit"
|
||||
}
|
||||
}
|
||||
},
|
||||
"breakdown": {
|
||||
"name": "详细分析",
|
||||
"description": "在特定时期中, 战车的详细分析",
|
||||
"body": {
|
||||
"total": "全部",
|
||||
"battles": "战斗场次",
|
||||
"wn8": "WN8",
|
||||
"winrate": "胜率",
|
||||
"damage": "伤害",
|
||||
"unknown_tank": "未知坦克 {id}"
|
||||
}
|
||||
},
|
||||
"debug": {
|
||||
"name": "侦错",
|
||||
"description": "机器人侦错信息",
|
||||
"body": {
|
||||
"title": "# 侦错\n\n",
|
||||
"version": "版本",
|
||||
"shard": {
|
||||
"label": "碎片",
|
||||
"default": "默认"
|
||||
},
|
||||
"uptime": "运行时间"
|
||||
}
|
||||
},
|
||||
"evolution": {
|
||||
"name": "演变",
|
||||
"description": "统计资料的演变",
|
||||
"groups": {
|
||||
"player": {
|
||||
"name": "玩家",
|
||||
"description": "玩家数据统计"
|
||||
},
|
||||
"tank": {
|
||||
"name": "坦克",
|
||||
"description": "坦克数据统计"
|
||||
}
|
||||
}
|
||||
},
|
||||
"inactive": {
|
||||
"name": "不活跃",
|
||||
"description": "列出公会中所有超过阈值的不活跃玩家",
|
||||
"options": {
|
||||
"threshold": {
|
||||
"name": "阈值",
|
||||
"description": "未上线天数( 默认:{days} 天)"
|
||||
}
|
||||
},
|
||||
"body": {
|
||||
"subtitle": "{days}+ 天未上线",
|
||||
"listing": "{days} 天"
|
||||
}
|
||||
},
|
||||
"full_stats": {
|
||||
"name": "完整统计资料",
|
||||
"description": "游戏内完整统计资料",
|
||||
"body": {
|
||||
"cards": {
|
||||
"games": {
|
||||
"title": "游戏",
|
||||
"winrate": "胜率",
|
||||
"battles": "战斗场次",
|
||||
"wins_losses": "胜利/失败"
|
||||
},
|
||||
"efficiency": {
|
||||
"title": "效率",
|
||||
"wn8": "WN8",
|
||||
"survival": "生存率",
|
||||
"accuracy": "命中率"
|
||||
},
|
||||
"lethality": {
|
||||
"title": "致命伤害",
|
||||
"average_damage": "平均伤害",
|
||||
"damage_per_tier": "各阶级伤害",
|
||||
"damage_ratio": "伤害比",
|
||||
"average_kills": "平均击毁"
|
||||
},
|
||||
"miscellaneous": {
|
||||
"title": "杂项",
|
||||
"average_tier": "平均阶级",
|
||||
"average_spots": "平均侦查",
|
||||
"average_xp": "平均经验",
|
||||
"kills_to_death_ratio": "击杀阵亡比"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"link": {
|
||||
"name": "链接",
|
||||
"description": "链接您的 Blitz 和 Discord 账户",
|
||||
"body": {
|
||||
"accounts_linked": "帐号已绑定",
|
||||
"no_role_permissions": {
|
||||
"title": "{name} 验证失败",
|
||||
"description": "我没有管理身份的权限。"
|
||||
}
|
||||
},
|
||||
"embed": {
|
||||
"title": "账户不正确?",
|
||||
"description": "再次使用此命令,从搜索结果中选择一个用户名。"
|
||||
}
|
||||
},
|
||||
"search_clans": {
|
||||
"name": "搜寻-公会资料",
|
||||
"description": "搜寻公会资料",
|
||||
"options": {
|
||||
"limit": {
|
||||
"name": "限制",
|
||||
"description": "公会结果的最大显示数量 (默认:{limit})"
|
||||
}
|
||||
},
|
||||
"body": {
|
||||
"title": "在地区 {region} 中搜索公会 {search}",
|
||||
"no_results": "没有找到该公会"
|
||||
}
|
||||
},
|
||||
"search_players": {
|
||||
"name": "搜索-玩家",
|
||||
"description": "搜索玩家",
|
||||
"options": {
|
||||
"limit": {
|
||||
"name": "限制",
|
||||
"description": "玩家结果的最大显示数量 (默认:{limit})"
|
||||
}
|
||||
},
|
||||
"body": {
|
||||
"title": "在地区 {region} 中搜索玩家 {search}",
|
||||
"no_results": "未找到玩家"
|
||||
}
|
||||
},
|
||||
"rating_leaderboard": {
|
||||
"name": "评价战斗-排行榜",
|
||||
"description": "评价战斗的统计数据",
|
||||
"subcommands": {
|
||||
"neighbors": {
|
||||
"name": "附近的",
|
||||
"description": "排行榜上附近的玩家"
|
||||
},
|
||||
"league": {
|
||||
"name": "段位",
|
||||
"description": "段位中的顶尖玩家"
|
||||
}
|
||||
},
|
||||
"options": {
|
||||
"limit": {
|
||||
"name": "限制",
|
||||
"description": "显示附近有多少玩家(默认:{count})"
|
||||
},
|
||||
"season": {
|
||||
"name": "赛季",
|
||||
"description": "赛季数 (默认:当前)",
|
||||
"choices": {
|
||||
"current": "{season} (当前)"
|
||||
}
|
||||
},
|
||||
"league": {
|
||||
"name": "段位",
|
||||
"description": "要显示的段位"
|
||||
}
|
||||
},
|
||||
"body": {
|
||||
"top_players": "前 {count} 玩家",
|
||||
"no_participation": "# {player} 没有在赛季 {season} 中进行过评价战斗\n\n该玩家没有参加该赛季或没有完成校准。",
|
||||
"no_ongoing_season": "# 没有进行中的赛季\n\n目前没有赛季。",
|
||||
"deleted_player": "已删除玩家 {id}",
|
||||
"neighbors": "对邻居进行评分",
|
||||
"more": "+ {count} 更多"
|
||||
}
|
||||
},
|
||||
"today": {
|
||||
"name": "今日",
|
||||
"description": "今天玩过的坦克和统计数据"
|
||||
},
|
||||
"stats": {
|
||||
"name": "统计资料",
|
||||
"description": "一段时间内的快速统计"
|
||||
},
|
||||
"owned_tanks": {
|
||||
"name": "已拥有的坦克",
|
||||
"description": "在一个等级中显示所有已拥有的坦克",
|
||||
"body": {
|
||||
"title": "# {name} 所拥有的 {tier} 阶坦克\n\n"
|
||||
}
|
||||
},
|
||||
"permissions": {
|
||||
"name": "权限",
|
||||
"description": "检查机器人是否拥有运行所需的权限",
|
||||
"body": {
|
||||
"title": "# 权限\n\n{body}",
|
||||
"view_channels": "查看频道:需要找到重新整理按钮使用的讯息",
|
||||
"read_message_history": "读取消息历史: 需要找到消息以刷新",
|
||||
"attach_files": "附加文件:需要将图像添加到基于图像的命令",
|
||||
"external_emojis": "外部表情:需要添加国家旗帜和坦克等级表情"
|
||||
}
|
||||
},
|
||||
"ping": {
|
||||
"name": "连接延迟",
|
||||
"description": "检查机器人是否处于活动状态。",
|
||||
"body": {
|
||||
"pong": "Pong 🏓",
|
||||
"pong_with_time": "Pong 🏓 - {time} 微秒"
|
||||
},
|
||||
"subcommands": {
|
||||
"blitzkit": {
|
||||
"name": "blitzkit",
|
||||
"description": "测试BlitzKit的ping值(延迟值)"
|
||||
},
|
||||
"wotb": {
|
||||
"name": "战车世界闪击战",
|
||||
"description": "测试坦克世界闪击战的ping值(延迟值)"
|
||||
}
|
||||
}
|
||||
},
|
||||
"player_info": {
|
||||
"name": "玩家信息",
|
||||
"description": "玩家基本信息",
|
||||
"body": {
|
||||
"title": "{name} 的信息",
|
||||
"nickname": "昵称",
|
||||
"battles": "战斗场次",
|
||||
"winrate": "胜率",
|
||||
"account_id": "账号ID",
|
||||
"created": "创建时间",
|
||||
"last_battle": "最后一场战斗"
|
||||
}
|
||||
},
|
||||
"rating": {
|
||||
"name": "评价战斗",
|
||||
"description": "评价战斗的统计数据",
|
||||
"subcommands": {
|
||||
"today": {
|
||||
"name": "今日",
|
||||
"description": "今日评价战斗统计数据"
|
||||
},
|
||||
"season": {
|
||||
"name": "赛季",
|
||||
"description": "本季评价战斗统计数据"
|
||||
}
|
||||
},
|
||||
"body": {
|
||||
"subtitle": {
|
||||
"today": "今日评价战斗统计数据",
|
||||
"season": "本季评价战斗统计数据"
|
||||
}
|
||||
},
|
||||
"errors": {
|
||||
"no_participation": "# {name} 未曾游玩评价战斗\n\n该玩家未参与本赛季的评价战斗。",
|
||||
"unrecorded_stats": "# 统计数据目前无法使用\n\nWargaming 可能暂停了服务器。 如果有连续的赛季,统计数据可能在24小时内提供。"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"website": {
|
||||
"redirect": {
|
||||
"title": "301: 已永久移动",
|
||||
@@ -741,14 +281,6 @@
|
||||
}
|
||||
},
|
||||
"home": {
|
||||
"pwa": {
|
||||
"title": "安装 BlitzKit 应用程序",
|
||||
"new": "新增",
|
||||
"checking": "正在检查兼容性……",
|
||||
"instructions": "Apple 设备的说明。",
|
||||
"install": "安装",
|
||||
"dismiss": "取消"
|
||||
},
|
||||
"discord": {
|
||||
"join_short": "加入超级酷的人群!",
|
||||
"join_long": "加入我们的Discord社群,和超酷的人一起聊天!",
|
||||
@@ -809,7 +341,7 @@
|
||||
"mixer": {
|
||||
"name": "组装",
|
||||
"button": "混合搭配",
|
||||
"description": "混合坦克模块",
|
||||
"description": "混搭不同坦克间的模块",
|
||||
"seo_description": "《坦克世界:闪击战》的车体, 炮塔, 主炮混合搭配",
|
||||
"screenshot": "屏幕截图",
|
||||
"randomize": "随机搭配"
|
||||
@@ -984,7 +516,7 @@
|
||||
"equalizer": {
|
||||
"title": "Equalizer",
|
||||
"equalize": "Equalize",
|
||||
"beta": "Beta"
|
||||
"beta": "测试版"
|
||||
},
|
||||
"modules": {
|
||||
"title": "坦克模块",
|
||||
@@ -1018,8 +550,8 @@
|
||||
"title": "属性",
|
||||
"compare": {
|
||||
"label": "比较",
|
||||
"class": "{tier} {class}",
|
||||
"tier": "All tier {tier}",
|
||||
"class": "{tier} 阶的 {class}",
|
||||
"tier": "所有{tier} 阶的",
|
||||
"all": "所有坦克"
|
||||
},
|
||||
"values": {
|
||||
@@ -1102,8 +634,8 @@
|
||||
"shellCapacity": "携弹量",
|
||||
"gunType": "炮管类型",
|
||||
"penetrationAt250m": "两百五十米处的穿透力",
|
||||
"burstShells": "Burst shell count",
|
||||
"burstInterShell": "Burst inter-shell"
|
||||
"burstShells": "爆破计数",
|
||||
"burstInterShell": "爆破弹"
|
||||
}
|
||||
},
|
||||
"firepower": {
|
||||
@@ -1156,7 +688,7 @@
|
||||
"skills": {
|
||||
"clear": "清除",
|
||||
"maximize": "最大化",
|
||||
"equalize": "Equalize"
|
||||
"equalize": "平衡"
|
||||
},
|
||||
"modules": {
|
||||
"stock": "白板",
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
{
|
||||
"name": "@blitzkit/scripts",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"discover-ids": "bun src/discoverIds/index.ts",
|
||||
"build-protos": "bun src/protos.ts",
|
||||
"record-performance": "bun src/recordPerformance/index.ts",
|
||||
"download-client": "bun src/downloadClient/index.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"@blitzkit/closed": "workspace:*",
|
||||
"@blitzkit/core": "workspace:*",
|
||||
@@ -34,20 +41,5 @@
|
||||
"unzipit": "^1.4.3",
|
||||
"yaml": "^2.8.1"
|
||||
},
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"build:assets": "bun src/buildAssets/index.ts",
|
||||
"build:averages": "bun src/averages.ts",
|
||||
"setup:depotdownloader": "bun src/setupDepotDownloader.ts",
|
||||
"setup:patches": "bun src/applyPatches.ts",
|
||||
"build:reviews": "bun src/reviews.ts",
|
||||
"build:ids": "bun src/discoverIds/index.ts",
|
||||
"build:ratingleaderboard": "bun src/buildRatingLeaderboard.ts",
|
||||
"build:proxyclient": "bun src/buildProxyClient.ts",
|
||||
"build:catalogitemaccesssor": "bun src/buildCatalogItemAccessor.ts",
|
||||
"prunestrings": "bun src/pruneStrings.ts",
|
||||
"build:protos": "bun src/protos.ts",
|
||||
"patchnotes": "bun src/patchNotes.ts"
|
||||
},
|
||||
"type": "module"
|
||||
}
|
||||
@@ -1,229 +0,0 @@
|
||||
import {
|
||||
AverageDefinitions,
|
||||
AverageDefinitionsAllStats,
|
||||
AverageDefinitionsEntry,
|
||||
type IndividualTankStats,
|
||||
REGIONS,
|
||||
type Region,
|
||||
Samples,
|
||||
averageDefinitionsAllStatsKeys,
|
||||
emptySamples,
|
||||
getAccountInfo,
|
||||
getTankStats,
|
||||
idToRegion,
|
||||
} from "@blitzkit/core";
|
||||
import { chunk, times } from "lodash-es";
|
||||
import { AssetUploader } from "./core/github/assetUploader";
|
||||
import { fetchPreDiscoveredIds } from "./core/github/fetchPreDiscoveredIds";
|
||||
|
||||
interface DataPoint {
|
||||
x: number;
|
||||
y: number;
|
||||
w: number;
|
||||
}
|
||||
|
||||
const MINUTE = 60 * 1000;
|
||||
const HOUR = 60 * MINUTE;
|
||||
const DAY = 24 * HOUR;
|
||||
// const MAX_ACTIVITY_TIME = 120 * DAY;
|
||||
// const MIN_BATTLES = 5000;
|
||||
const RUN_TIME = 5 * HOUR + 55 * MINUTE;
|
||||
const THREADS = 10;
|
||||
const PLAYER_IDS_PER_CALL = 100;
|
||||
|
||||
const startTime = Date.now();
|
||||
const preDiscoveredIds = await fetchPreDiscoveredIds();
|
||||
const playerIds: Record<Region, number[][]> = {
|
||||
asia: chunk(
|
||||
preDiscoveredIds.filter((id) => idToRegion(id) === "asia"),
|
||||
PLAYER_IDS_PER_CALL,
|
||||
),
|
||||
com: chunk(
|
||||
preDiscoveredIds.filter((id) => idToRegion(id) === "com"),
|
||||
PLAYER_IDS_PER_CALL,
|
||||
),
|
||||
eu: chunk(
|
||||
preDiscoveredIds.filter((id) => idToRegion(id) === "eu"),
|
||||
PLAYER_IDS_PER_CALL,
|
||||
),
|
||||
};
|
||||
let regionIndex = 0;
|
||||
const samples: Samples = { ...emptySamples };
|
||||
const availableRegions = [...REGIONS];
|
||||
const tankIds: number[] = [];
|
||||
const tanksSorted: Record<number, IndividualTankStats[]> = {};
|
||||
let postWorkRequested = false;
|
||||
|
||||
times(THREADS, async () => {
|
||||
while (availableRegions.length > 0 && startTime + RUN_TIME > Date.now()) {
|
||||
const region = availableRegions[regionIndex];
|
||||
const regionIds = playerIds[region];
|
||||
const [ids] = regionIds.splice(
|
||||
Math.floor(Math.random() * regionIds.length),
|
||||
1,
|
||||
);
|
||||
const accountInfo = await getAccountInfo(region, ids, undefined, {
|
||||
fields: "last_battle_time,statistics.all.battles",
|
||||
});
|
||||
|
||||
const filteredIds = ids.filter((_, index) => {
|
||||
const info = accountInfo[index];
|
||||
|
||||
if (info === null) return false;
|
||||
|
||||
const timeSinceLastActivity = Date.now() - info.last_battle_time * 1000;
|
||||
|
||||
samples.total++;
|
||||
if (timeSinceLastActivity <= 120 * DAY) samples.d_120++;
|
||||
if (timeSinceLastActivity <= 90 * DAY) samples.d_90++;
|
||||
if (timeSinceLastActivity <= 60 * DAY) samples.d_60++;
|
||||
if (timeSinceLastActivity <= 30 * DAY) samples.d_30++;
|
||||
if (timeSinceLastActivity <= 7 * DAY) samples.d_7++;
|
||||
if (timeSinceLastActivity <= 1 * DAY) samples.d_1++;
|
||||
|
||||
return true;
|
||||
|
||||
// return (
|
||||
// timeSinceLastActivity <= MAX_ACTIVITY_TIME &&
|
||||
// info.statistics.all.battles > MIN_BATTLES
|
||||
// );
|
||||
});
|
||||
|
||||
const players = await Promise.all(
|
||||
filteredIds.map((id) =>
|
||||
getTankStats(region, id, {
|
||||
fields: "last_battle_time,battle_life_time,all,tank_id",
|
||||
}),
|
||||
),
|
||||
);
|
||||
|
||||
players.forEach((tanks) => {
|
||||
tanks?.forEach((tank) => {
|
||||
if (tank.all.battles === 0) return;
|
||||
|
||||
if (!tankIds.includes(tank.tank_id)) {
|
||||
console.log(
|
||||
`Found new tank: ${tank.tank_id} (${tankIds.length + 1})`,
|
||||
);
|
||||
tankIds.push(tank.tank_id);
|
||||
tanksSorted[tank.tank_id] = [];
|
||||
}
|
||||
|
||||
tanksSorted[tank.tank_id].push(tank);
|
||||
});
|
||||
});
|
||||
|
||||
if (regionIds.length === 0 && availableRegions.includes(region)) {
|
||||
availableRegions.splice(availableRegions.indexOf(region), 1);
|
||||
}
|
||||
regionIndex = (regionIndex + 1) % availableRegions.length;
|
||||
}
|
||||
|
||||
if (!postWorkRequested) {
|
||||
postWorkRequested = true;
|
||||
postWork();
|
||||
}
|
||||
});
|
||||
|
||||
async function postWork() {
|
||||
console.log(
|
||||
`Generating statistics based on ${samples.d_120.toLocaleString()} players (${samples.total.toLocaleString()} checked in total) and ${
|
||||
tankIds.length
|
||||
} tanks...`,
|
||||
);
|
||||
|
||||
using uploader = new AssetUploader("averages");
|
||||
const averages: Record<number, AverageDefinitionsEntry> = {};
|
||||
|
||||
tankIds.forEach((id) => {
|
||||
const tanksSortedEntry = tanksSorted[id];
|
||||
// const tanks = tanksSortedEntry.filter(
|
||||
// (tank) => Date.now() - tank.last_battle_time * 1000 <= MAX_ACTIVITY_TIME,
|
||||
// );
|
||||
const tanks = tanksSortedEntry;
|
||||
const entry: {
|
||||
mu: Partial<Record<keyof AverageDefinitionsAllStats, number>>;
|
||||
sigma: Partial<Record<keyof AverageDefinitionsAllStats, number>>;
|
||||
r: Partial<Record<keyof AverageDefinitionsAllStats, number>>;
|
||||
samples: Samples;
|
||||
} = {
|
||||
mu: {},
|
||||
sigma: {},
|
||||
r: {},
|
||||
samples: { ...emptySamples },
|
||||
};
|
||||
|
||||
tanks.forEach((tank) => {
|
||||
const timeSinceLastActivity = Date.now() - tank.last_battle_time * 1000;
|
||||
|
||||
entry.samples!.total++;
|
||||
if (timeSinceLastActivity <= 120 * DAY) entry.samples!.d_120++;
|
||||
if (timeSinceLastActivity <= 90 * DAY) entry.samples!.d_90++;
|
||||
if (timeSinceLastActivity <= 60 * DAY) entry.samples!.d_60++;
|
||||
if (timeSinceLastActivity <= 30 * DAY) entry.samples!.d_30++;
|
||||
if (timeSinceLastActivity <= 7 * DAY) entry.samples!.d_7++;
|
||||
if (timeSinceLastActivity <= 1 * DAY) entry.samples!.d_1++;
|
||||
});
|
||||
|
||||
const dataWY = tanks.map((tank) => ({
|
||||
w: tank.all.battles,
|
||||
y: tank.all.wins / tank.all.battles,
|
||||
}));
|
||||
|
||||
averageDefinitionsAllStatsKeys.forEach((key) => {
|
||||
const data: DataPoint[] = dataWY.map(({ w, y }, index) => ({
|
||||
w,
|
||||
x:
|
||||
(key === "battle_life_time"
|
||||
? tanks[index].battle_life_time
|
||||
: tanks[index].all[key]) / w,
|
||||
y,
|
||||
}));
|
||||
|
||||
if (data.length === 0) return;
|
||||
|
||||
function sum(slicer: (data: DataPoint) => number) {
|
||||
return data.reduce(
|
||||
(accumulator, data) => accumulator + slicer(data),
|
||||
0,
|
||||
);
|
||||
}
|
||||
|
||||
const sum_w = sum(({ w }) => w);
|
||||
const sum_wx = sum(({ w, x }) => w * x);
|
||||
const sum_wy = sum(({ w, y }) => w * y);
|
||||
const x_bar = sum_wx / sum_w;
|
||||
const y_bar = sum_wy / sum_w;
|
||||
// undo normalization for mu to get a simple average
|
||||
const mu = sum(({ w, x }) => w * x) / samples.d_120;
|
||||
|
||||
const sigma_numerator = sum(({ w, x }) => w * (x - x_bar) ** 2);
|
||||
const sigma = Math.sqrt(sigma_numerator / sum_w);
|
||||
|
||||
const r_numerator = sum(({ w, x, y }) => w * (x - x_bar) * (y - y_bar));
|
||||
const r_denominator_x = sum(({ w, x }) => w * (x - x_bar) ** 2);
|
||||
const r_denominator_y = sum(({ w, y }) => w * (y - y_bar) ** 2);
|
||||
const r = r_numerator / Math.sqrt(r_denominator_x * r_denominator_y);
|
||||
|
||||
entry.mu[key] = mu;
|
||||
entry.sigma[key] = sigma;
|
||||
entry.r[key] = isNaN(r) ? 0 : r;
|
||||
});
|
||||
|
||||
averages[id] = entry as AverageDefinitionsEntry;
|
||||
});
|
||||
|
||||
const time = Date.now();
|
||||
const averageDefinitions = {
|
||||
averages,
|
||||
samples,
|
||||
time,
|
||||
} satisfies AverageDefinitions;
|
||||
|
||||
await uploader.add({
|
||||
path: "averages.pb",
|
||||
content: AverageDefinitions.encode(averageDefinitions).finish(),
|
||||
});
|
||||
|
||||
await uploader.flush();
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
import { readdir, readFile, writeFile } from "fs/promises";
|
||||
|
||||
const SOURCES = "../../packages/closed/protos";
|
||||
const TARGET = "../../packages/closed/src/unreal/catalogItemAccessor.ts";
|
||||
|
||||
const componentPattern = /^message (\w+)Component {/gm;
|
||||
|
||||
const files = await readdir(SOURCES).then((files) =>
|
||||
files.filter(
|
||||
(file) =>
|
||||
file.startsWith("blitz_static_") && file.endsWith("_component.proto")
|
||||
)
|
||||
);
|
||||
|
||||
const imports: { name: string; file: string }[] = [];
|
||||
|
||||
for (const file of files) {
|
||||
const content = await readFile(`${SOURCES}/${file}`).then((buffer) =>
|
||||
buffer.toString()
|
||||
);
|
||||
const components = content.matchAll(componentPattern);
|
||||
|
||||
for (const match of components) {
|
||||
const name = match[1];
|
||||
const duplicate = imports.find((_import) => _import.name === name);
|
||||
|
||||
if (duplicate) {
|
||||
console.warn(
|
||||
`Duplicate component ${name} across ${duplicate.file}.proto and ${file}`
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
const importFile = file.replace(".proto", "");
|
||||
|
||||
imports.push({ name, file: importFile });
|
||||
}
|
||||
}
|
||||
|
||||
let content = "";
|
||||
|
||||
for (const _import of imports) {
|
||||
content += `import { ${_import.name}Component } from "@protos/${_import.file}";\n`;
|
||||
}
|
||||
|
||||
content +=
|
||||
'import { BaseCatalogItemAccessor } from "./baseCatalogItemAccessor";\n\n';
|
||||
content +=
|
||||
"export class CatalogItemAccessor extends BaseCatalogItemAccessor {\n";
|
||||
|
||||
for (const _import of imports) {
|
||||
const strippedName = _import.name.replace("BlitzStatic", "");
|
||||
const defaultName = strippedName[0].toLowerCase() + strippedName.slice(1);
|
||||
|
||||
content += ` ${strippedName}(name = "${defaultName}Component") {\n`;
|
||||
content += ` return this.component(name, ${_import.name}Component);\n`;
|
||||
content += " }\n";
|
||||
}
|
||||
|
||||
content += "}\n";
|
||||
|
||||
await writeFile(TARGET, content);
|
||||
@@ -1,40 +0,0 @@
|
||||
import { readFile, writeFile } from "fs/promises";
|
||||
|
||||
const IMPORT = "@protos/auto_legacy_proxy_client";
|
||||
const SOURCE = "../../packages/closed/protos/auto_legacy_proxy_client.proto";
|
||||
const TARGET = "../../packages/closed/src/unreal/methodPopulatedProxyClient.ts";
|
||||
|
||||
const requestPattern = /^message (\w+)Request {/gm;
|
||||
const source = await readFile(SOURCE).then((buffer) => buffer.toString());
|
||||
const requests = source.matchAll(requestPattern);
|
||||
|
||||
const imports: string[] = [];
|
||||
const names: string[] = [];
|
||||
|
||||
for (const match of requests) {
|
||||
const name = match[1];
|
||||
|
||||
imports.push(`${name}Request`, `${name}Response`);
|
||||
names.push(name);
|
||||
}
|
||||
|
||||
let content = "";
|
||||
|
||||
content += "import {\n";
|
||||
content += imports.map((i) => ` ${i},`).join("\n");
|
||||
content += `\n} from "${IMPORT}";\n`;
|
||||
|
||||
content += 'import { BaseProxyClient } from "./baseProxyClient";\n\n';
|
||||
|
||||
content +=
|
||||
"export abstract class MethodPopulatedProxyClient extends BaseProxyClient {\n";
|
||||
content += names
|
||||
.map((name) => {
|
||||
return ` ${name}(data: ${name}Request) {
|
||||
return this.request("${name}Request", ${name}Request, data, ${name}Response);
|
||||
}\n`;
|
||||
})
|
||||
.join("");
|
||||
content += "}\n";
|
||||
|
||||
await writeFile(TARGET, content);
|
||||
@@ -0,0 +1,58 @@
|
||||
import { $ } from "bun";
|
||||
import { mkdir, rm } from "node:fs/promises";
|
||||
|
||||
export class GitObjectStorage {
|
||||
constructor(
|
||||
private repo: string,
|
||||
private base: string,
|
||||
private token?: string,
|
||||
) {}
|
||||
|
||||
async init() {
|
||||
await rm(this.base, { recursive: true, force: true });
|
||||
|
||||
console.log(`Cloning ${this.repo} to ${this.base}`);
|
||||
|
||||
const url = this.token
|
||||
? `https://x-access-token:${this.token}@github.com/${this.repo}.git`
|
||||
: `https://github.com/${this.repo}.git`;
|
||||
|
||||
await $`git clone --depth 1 ${url} ${this.base}`;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
async commit() {
|
||||
const shell = $.cwd(this.base);
|
||||
|
||||
await shell`git add .`.quiet();
|
||||
await shell`git commit --amend --reset-author -m "ids update ${new Date().toISOString()}"`.quiet();
|
||||
await shell`git push --force-with-lease`;
|
||||
}
|
||||
|
||||
async mkdir(path: string) {
|
||||
await mkdir(`${this.base}/${path}`, { recursive: true });
|
||||
}
|
||||
|
||||
async rm(path: string) {
|
||||
await rm(`${this.base}/${path}`, { force: true });
|
||||
}
|
||||
|
||||
async write(path: string, bytes: Uint8Array | string) {
|
||||
await Bun.write(`${this.base}/${path}`, bytes);
|
||||
}
|
||||
|
||||
file(path: string) {
|
||||
return Bun.file(`${this.base}/${path}`);
|
||||
}
|
||||
|
||||
async bytes(path: string) {
|
||||
const file = this.file(path);
|
||||
return await file.bytes();
|
||||
}
|
||||
|
||||
async json<Type>(path: string) {
|
||||
const file = this.file(path);
|
||||
return (await file.json()) as Type;
|
||||
}
|
||||
}
|
||||
+7
@@ -1,3 +1,5 @@
|
||||
import { decompress } from "lz4js";
|
||||
|
||||
export class IdArray {
|
||||
constructor(
|
||||
private array: Uint32Array = new Uint32Array(),
|
||||
@@ -57,6 +59,11 @@ export class IdArray {
|
||||
return new IdArray(uintArray, size);
|
||||
}
|
||||
|
||||
static fromCompressed(bytes: Uint8Array) {
|
||||
const decompressed = decompress(bytes);
|
||||
return this.fromBytes(decompressed);
|
||||
}
|
||||
|
||||
static fromArray(array: number[]) {
|
||||
const uintArray = new Uint32Array(this.nextPowerOf2(array.length));
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
export const API_RATE = 10; // 10Hz
|
||||
export const MAX_IDS_PER_CALL = 100;
|
||||
export const MAX_DRY_STREAK = 10_000;
|
||||
|
||||
export const ACCOMMODATED_ID_COUNT = 500_000_000; // 500M ids
|
||||
|
||||
const PERFORMANCE_RUN_TIME = (5 * 60 + 30) * 60;
|
||||
export const IDS_PER_CHUNK = PERFORMANCE_RUN_TIME * API_RATE;
|
||||
export const CHUNK_COUNT = Math.ceil(ACCOMMODATED_ID_COUNT / IDS_PER_CHUNK);
|
||||
@@ -1,89 +1,45 @@
|
||||
import { $ } from "bun";
|
||||
import { range } from "lodash-es";
|
||||
import { compress, decompress } from "lz4js";
|
||||
import { mkdir, rm } from "node:fs/promises";
|
||||
import { compress } from "lz4js";
|
||||
import { exit } from "node:process";
|
||||
import { IdArray } from "./idArray";
|
||||
import { GitObjectStorage } from "../core/blitzkit/gitObjectStorage";
|
||||
import { IdArray } from "../core/blitzkit/idArray";
|
||||
import { CHUNK_COUNT, MAX_DRY_STREAK, MAX_IDS_PER_CALL } from "./constants";
|
||||
import { atMaxRate } from "./time";
|
||||
import { IdsManifest, QuickInfo, RegionDescriptor } from "./types";
|
||||
|
||||
interface ManifestV1 {
|
||||
version: 1;
|
||||
last_verified: number;
|
||||
}
|
||||
const storage = await new GitObjectStorage(
|
||||
"blitzkit/data-ids",
|
||||
"../../temp/ids",
|
||||
import.meta.env.GH_TOKEN,
|
||||
).init();
|
||||
|
||||
interface RegionDescriptor {
|
||||
domain: string;
|
||||
seed: number;
|
||||
max: number;
|
||||
streak: number;
|
||||
}
|
||||
|
||||
export interface QuickInfo {
|
||||
status: string;
|
||||
data: Record<string, {} | null>;
|
||||
}
|
||||
|
||||
const TEMP = "../../temp";
|
||||
const WORKING_DIR = `${TEMP}/ids`;
|
||||
const CHUNKS_DIR = `${WORKING_DIR}/chunks`;
|
||||
const REPO = "blitzkit/ids";
|
||||
|
||||
const ACCOMMODATED_ID_COUNT = 10_000_000_000; // 10B ids
|
||||
const MAX_BYTES_PER_CHUNK = 100 * 1_000_000; // 100MB
|
||||
|
||||
const MAX_IDS_PER_CALL = 100;
|
||||
const API_RATE = 10; // 10Hz
|
||||
const MAX_DRY_STREAK = 10_000;
|
||||
|
||||
const chunkCount = Math.ceil(
|
||||
(ACCOMMODATED_ID_COUNT * Uint32Array.BYTES_PER_ELEMENT) / MAX_BYTES_PER_CHUNK,
|
||||
);
|
||||
|
||||
console.log(
|
||||
`${chunkCount.toLocaleString()} will be needed for ${ACCOMMODATED_ID_COUNT.toLocaleString()} ids`,
|
||||
);
|
||||
|
||||
const t0 = performance.now();
|
||||
const maxT = 5 * 60 * 60 * 1000; // 5hr
|
||||
const t1 = t0 + maxT;
|
||||
|
||||
await mkdir(TEMP, { recursive: true });
|
||||
await rm(WORKING_DIR, { recursive: true, force: true });
|
||||
|
||||
console.log(`Cloning ${REPO} to ${WORKING_DIR}`);
|
||||
|
||||
await $`git clone --depth 1 https://github.com/${REPO} ${WORKING_DIR}`;
|
||||
await mkdir(CHUNKS_DIR, { recursive: true });
|
||||
await storage.mkdir("chunks");
|
||||
|
||||
console.log(`Discovering pre-existing chunks...`);
|
||||
|
||||
const discoveredChunks: (IdArray | null)[] = [];
|
||||
|
||||
for (let i = 0; true; i++) {
|
||||
const path = `${CHUNKS_DIR}/chunk-${i}.dat.lz4`;
|
||||
const file = Bun.file(path);
|
||||
const manifest = await storage.json<IdsManifest>("manifest.json");
|
||||
|
||||
if (!(await file.exists())) break;
|
||||
|
||||
const bytes = await file.bytes();
|
||||
const uncompressed = decompress(bytes);
|
||||
|
||||
const ids = IdArray.fromBytes(uncompressed);
|
||||
for (let i = 0; i < manifest.chunks; i++) {
|
||||
const bytes = await storage.bytes(`chunks/chunk-${i}.dat.lz4`);
|
||||
const ids = IdArray.fromCompressed(bytes);
|
||||
|
||||
discoveredChunks.push(ids);
|
||||
}
|
||||
|
||||
console.log(`Found ${discoveredChunks.length} pre-existing chunks`);
|
||||
console.log(`Found ${manifest.chunks} pre-existing chunks`);
|
||||
|
||||
let chunks: IdArray[] = [];
|
||||
|
||||
if (discoveredChunks.length === chunkCount) {
|
||||
if (manifest.chunks === CHUNK_COUNT) {
|
||||
console.log("Pre-existing chunking is consistent, passing as-is...");
|
||||
|
||||
chunks = discoveredChunks as IdArray[];
|
||||
} else {
|
||||
console.log("Pre-existing chunking is not consistent, re-chunking...");
|
||||
|
||||
chunks = Array.from({ length: chunkCount }).map(() => new IdArray());
|
||||
chunks = Array.from({ length: CHUNK_COUNT }).map(() => new IdArray());
|
||||
|
||||
for (let i = 0; i < discoveredChunks.length; i++) {
|
||||
const ids = discoveredChunks[i];
|
||||
@@ -91,7 +47,7 @@ if (discoveredChunks.length === chunkCount) {
|
||||
|
||||
for (let j = 0; j < size; j++) {
|
||||
const id = ids!.get(j);
|
||||
const chunk = chunks[id % chunkCount];
|
||||
const chunk = chunks[id % CHUNK_COUNT];
|
||||
|
||||
chunk.push(id);
|
||||
}
|
||||
@@ -102,17 +58,20 @@ if (discoveredChunks.length === chunkCount) {
|
||||
console.log("Sorting chunks...");
|
||||
|
||||
for (let i = 0; i < chunks.length; i++) chunks[i].sort();
|
||||
|
||||
manifest.chunks = CHUNK_COUNT;
|
||||
manifest.last_verified = manifest.last_verified % CHUNK_COUNT;
|
||||
}
|
||||
|
||||
const regions: RegionDescriptor[] = [
|
||||
{ domain: "eu", seed: 5e8, max: 10e8 - 1, streak: 0 },
|
||||
{ domain: "com", seed: 10e8, max: 20e8 - 1, streak: 0 },
|
||||
{ domain: "asia", seed: 20e8, max: 31e8 - 1, streak: 0 },
|
||||
{ domain: "eu", seed: 5e8, max: 10e8 - 1, dry_streak: 0 },
|
||||
{ domain: "com", seed: 10e8, max: 20e8 - 1, dry_streak: 0 },
|
||||
{ domain: "asia", seed: 20e8, max: 31e8 - 1, dry_streak: 0 },
|
||||
];
|
||||
|
||||
console.log("Finding new seed ids...");
|
||||
|
||||
for (let i = 0; i < chunkCount; i++) {
|
||||
for (let i = 0; i < manifest.chunks; i++) {
|
||||
const chunk = chunks[i];
|
||||
const size = chunk.size();
|
||||
|
||||
@@ -141,29 +100,27 @@ async function save() {
|
||||
|
||||
console.log("Saving chunks...");
|
||||
|
||||
await rm(`${CHUNKS_DIR}/*`, { force: true });
|
||||
await storage.rm("chunks/*");
|
||||
|
||||
let totalFound = 0;
|
||||
|
||||
for (let i = 0; i < chunks.length; i++) {
|
||||
const path = `${CHUNKS_DIR}/chunk-${i}.dat.lz4`;
|
||||
const chunk = chunks[i];
|
||||
const bytes = chunk.toBytes();
|
||||
const compressed = compress(bytes);
|
||||
|
||||
totalFound += chunk.size();
|
||||
|
||||
await Bun.write(path, compressed);
|
||||
await storage.write(`chunks/chunk-${i}.dat.lz4`, compressed);
|
||||
}
|
||||
|
||||
const git = $.cwd(WORKING_DIR);
|
||||
manifest.total_count = totalFound;
|
||||
|
||||
await git`git add .`.quiet();
|
||||
await git`git commit --amend -m "ids update ${new Date().toISOString()}"`.quiet();
|
||||
await git`git push --force-with-lease`.quiet();
|
||||
await storage.write("manifest.json", JSON.stringify(manifest, null, 2));
|
||||
await storage.commit();
|
||||
|
||||
console.log(
|
||||
`Committed ${totalFound.toLocaleString()} total ids across ${chunkCount} chunks`,
|
||||
`Committed ${totalFound.toLocaleString()} total ids across ${manifest.chunks} chunks`,
|
||||
);
|
||||
|
||||
exit(0);
|
||||
@@ -172,24 +129,27 @@ async function save() {
|
||||
process.on("SIGINT", save);
|
||||
process.on("SIGTERM", save);
|
||||
|
||||
console.log("Starting discovery loop...");
|
||||
|
||||
const queue: { region: RegionDescriptor; url: string; size: number }[] = [];
|
||||
const applicationId = import.meta.env.PUBLIC_WARGAMING_APPLICATION_ID;
|
||||
const fields = "account_id%2C-account_id";
|
||||
let regionI = 0;
|
||||
|
||||
function fillQueue() {
|
||||
if (queue.length >= 1) return;
|
||||
console.log("Starting discovery loop...");
|
||||
|
||||
atMaxRate(async ({ _break: break1 }) => {
|
||||
if (regions.length === 0) {
|
||||
console.log("All regions exhausted, exiting discovery loop...");
|
||||
return break1();
|
||||
}
|
||||
|
||||
regionI = (regionI + 1) % regions.length;
|
||||
const region = regions[regionI];
|
||||
|
||||
if (region.streak >= MAX_DRY_STREAK) {
|
||||
if (region.dry_streak >= MAX_DRY_STREAK) {
|
||||
console.log(
|
||||
`Removing region ${region.domain} removed due to ${region.streak} dry streak...`,
|
||||
`Removing region ${region.domain} removed due to ${region.dry_streak} dry streak...`,
|
||||
);
|
||||
regions.splice(regionI, 1);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -206,62 +166,47 @@ function fillQueue() {
|
||||
fields
|
||||
}&account_id=${accountIds}`;
|
||||
|
||||
queue.push({ region, url, size: idRange.length });
|
||||
atMaxRate(async ({ _break: break2 }) => {
|
||||
if (idRange.length < MAX_IDS_PER_CALL) {
|
||||
console.log(
|
||||
`Removing region ${region.domain} removed due to ID range exhaustion...`,
|
||||
);
|
||||
regions.splice(regionI, 1);
|
||||
}
|
||||
|
||||
if (idRange.length < MAX_IDS_PER_CALL) {
|
||||
console.log(
|
||||
`Removing region ${region.domain} removed due to ID range exhaustion...`,
|
||||
);
|
||||
regions.splice(regionI, 1);
|
||||
}
|
||||
}
|
||||
const response = await fetch(url);
|
||||
const data = (await response.json()) as QuickInfo;
|
||||
|
||||
function sleep() {
|
||||
return new Promise((resolve) => setTimeout(resolve, 1000 / API_RATE));
|
||||
}
|
||||
if (data.status !== "ok") {
|
||||
console.warn("Failed API call; trying again...");
|
||||
return;
|
||||
}
|
||||
|
||||
while (performance.now() < t1 && regions.length > 0) {
|
||||
await sleep();
|
||||
let foundIds = 0;
|
||||
|
||||
fillQueue();
|
||||
for (const key in data.data) {
|
||||
const value = data.data[key];
|
||||
|
||||
if (queue.length === 0) {
|
||||
console.log("Queue empty, ending discovery loop...");
|
||||
break;
|
||||
}
|
||||
if (value === null) continue;
|
||||
|
||||
const request = queue.shift()!;
|
||||
const response = await fetch(request.url);
|
||||
const data = (await response.json()) as QuickInfo;
|
||||
foundIds++;
|
||||
|
||||
if (data.status !== "ok") {
|
||||
console.warn("Failed API call; pushing back into queue...");
|
||||
queue.push(request);
|
||||
const id = Number(key);
|
||||
const chunkIndex = id % manifest.chunks;
|
||||
const chunk = chunks[chunkIndex];
|
||||
|
||||
continue;
|
||||
}
|
||||
chunk.push(id);
|
||||
}
|
||||
|
||||
let foundIds = 0;
|
||||
if (foundIds === 0) {
|
||||
region.dry_streak += idRange.length;
|
||||
} else {
|
||||
region.dry_streak = 0;
|
||||
// console.log(`Found ${foundIds} ids in ${request.region.domain}`);
|
||||
}
|
||||
|
||||
for (const key in data.data) {
|
||||
const value = data.data[key];
|
||||
|
||||
if (value === null) continue;
|
||||
|
||||
foundIds++;
|
||||
|
||||
const id = Number(key);
|
||||
const chunkIndex = id % chunkCount;
|
||||
const chunk = chunks[chunkIndex];
|
||||
|
||||
chunk.push(id);
|
||||
}
|
||||
|
||||
if (foundIds === 0) {
|
||||
request.region.streak += request.size;
|
||||
} else {
|
||||
// console.log(`Found ${foundIds} ids in ${request.region.domain}`);
|
||||
}
|
||||
}
|
||||
break2();
|
||||
});
|
||||
});
|
||||
|
||||
await save();
|
||||
@@ -0,0 +1,45 @@
|
||||
import { API_RATE } from "./constants";
|
||||
|
||||
const MAX_COMPUTE_TIME = (5 * 60 + 55) * 60 * 1000; // 5hr 55min
|
||||
|
||||
const t0 = performance.now();
|
||||
const t1 = t0 + MAX_COMPUTE_TIME;
|
||||
|
||||
export function withinTimeLimit() {
|
||||
return performance.now() < t1;
|
||||
}
|
||||
|
||||
export function sleep(t: number) {
|
||||
return new Promise((resolve) => setTimeout(resolve, t));
|
||||
}
|
||||
|
||||
interface MethodContext {
|
||||
_break(): void;
|
||||
}
|
||||
|
||||
let lastT = 0;
|
||||
const maxDelta = 1000 / API_RATE;
|
||||
const DELTA_BUFFER = 0;
|
||||
export async function atMaxRate(method: (context: MethodContext) => void) {
|
||||
let isBroken = false;
|
||||
|
||||
const context: MethodContext = {
|
||||
_break() {
|
||||
isBroken = true;
|
||||
},
|
||||
};
|
||||
|
||||
while (!isBroken) {
|
||||
if (!withinTimeLimit()) break;
|
||||
|
||||
const t = performance.now();
|
||||
const delta = t - lastT;
|
||||
|
||||
if (delta < maxDelta) {
|
||||
await sleep(maxDelta - delta + DELTA_BUFFER);
|
||||
}
|
||||
|
||||
method(context);
|
||||
lastT = t;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
export type IdsManifest = IdsManifestV1;
|
||||
|
||||
interface IdsManifestV1 {
|
||||
version: 1;
|
||||
last_verified: number;
|
||||
chunks: number;
|
||||
total_count: number;
|
||||
}
|
||||
|
||||
export interface RegionDescriptor {
|
||||
domain: string;
|
||||
seed: number;
|
||||
max: number;
|
||||
dry_streak: number;
|
||||
}
|
||||
|
||||
export interface QuickInfo {
|
||||
status: string;
|
||||
data: Record<string, {} | null>;
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
// dava engine has a lot of tiny files, this is faster
|
||||
export const DEPOT_DOWNLOADER_MAX_DOWNLOADS = 256;
|
||||
export const DEPOT_DOWNLOADER_OUTPUT = "../../temp/depotdownloader";
|
||||
export const DEPOT_DOWNLOADER_EXECUTABLE = `${DEPOT_DOWNLOADER_OUTPUT}/DepotDownloader`;
|
||||
|
||||
export const ARIA2_OUTPUT = "../../temp/aria2";
|
||||
export const ARIA2_EXECUTABLE = `${ARIA2_OUTPUT}/aria2c`;
|
||||
|
||||
export const WGPKG_DIR = "../../temp/wgpkgs";
|
||||
@@ -0,0 +1,98 @@
|
||||
import { assertSecret } from "@blitzkit/core";
|
||||
import { $ } from "bun";
|
||||
import { mkdir, rm } from "node:fs/promises";
|
||||
import {
|
||||
DEPOT_DOWNLOADER_EXECUTABLE,
|
||||
DEPOT_DOWNLOADER_MAX_DOWNLOADS,
|
||||
DEPOT_DOWNLOADER_OUTPUT,
|
||||
WGPKG_DIR,
|
||||
} from "./constants";
|
||||
import { QuickGitHubRelease } from "./types";
|
||||
|
||||
const provider = assertSecret(import.meta.env.CLIENT_PROVIDER);
|
||||
const source = assertSecret(import.meta.env.CLIENT_SOURCE);
|
||||
const dir = assertSecret(import.meta.env.CLIENT_DIR);
|
||||
|
||||
await rm(dir, { recursive: true, force: true });
|
||||
await mkdir(dir, { recursive: true });
|
||||
|
||||
if (provider === "steam") {
|
||||
const [id, platform] = source.split("/");
|
||||
|
||||
console.log("Downloading Depot Downloader...");
|
||||
|
||||
const releases = await fetch(
|
||||
"https://api.github.com/repos/SteamRE/DepotDownloader/releases/latest",
|
||||
).then((response) => response.json() as Promise<QuickGitHubRelease>);
|
||||
const asset = releases.assets.find((asset) =>
|
||||
asset.name.includes("linux-x64"),
|
||||
);
|
||||
|
||||
if (!asset) {
|
||||
throw new Error("No linux-x64 asset found for Steam DepotDownloader");
|
||||
}
|
||||
|
||||
await rm(DEPOT_DOWNLOADER_OUTPUT, { recursive: true, force: true });
|
||||
|
||||
await $`curl -L "${asset.browser_download_url}" -o "${DEPOT_DOWNLOADER_OUTPUT}.zip"`;
|
||||
await $`unzip "${DEPOT_DOWNLOADER_OUTPUT}.zip" -d "${DEPOT_DOWNLOADER_OUTPUT}"`;
|
||||
await $`chmod +x "${DEPOT_DOWNLOADER_EXECUTABLE}"`;
|
||||
|
||||
console.log("Downloading client...");
|
||||
|
||||
const username = assertSecret(import.meta.env.STEAM_USERNAME);
|
||||
const password = assertSecret(import.meta.env.STEAM_PASSWORD);
|
||||
|
||||
await $`${DEPOT_DOWNLOADER_EXECUTABLE} -os ${
|
||||
platform
|
||||
} -app ${id} -username ${username} -password ${
|
||||
password
|
||||
} -dir ${dir} -max-downloads ${DEPOT_DOWNLOADER_MAX_DOWNLOADS}`;
|
||||
} else if (provider === "zip") {
|
||||
const url = assertSecret(import.meta.env.CLIENT_SOURCE);
|
||||
|
||||
console.log("Downloading and extracting zipped client...");
|
||||
|
||||
await mkdir(dir, { recursive: true });
|
||||
await $`curl -L "${url}" | bsdtar -xf- --strip-components=1 -C ${dir}`;
|
||||
} else if (provider === "wgpkg") {
|
||||
let index = 1;
|
||||
const urls: string[] = [];
|
||||
|
||||
console.log("Discovering packages...");
|
||||
|
||||
while (true) {
|
||||
const url = `${source}.${index.toString().padStart(3, "0")}`;
|
||||
const response = await fetch(url);
|
||||
|
||||
if (response.status === 200) {
|
||||
urls.push(url);
|
||||
} else if (response.status === 404) {
|
||||
break;
|
||||
} else {
|
||||
throw new Error(`Wargaming response error status: ${response.status}`);
|
||||
}
|
||||
|
||||
index++;
|
||||
}
|
||||
|
||||
console.log(`Downloading ${urls.length} packages...`);
|
||||
|
||||
await rm(WGPKG_DIR, { recursive: true });
|
||||
|
||||
const inputContent = urls
|
||||
.map((url) => {
|
||||
const name = url.split("/").pop()!;
|
||||
return `${url}\n out=${name}\n dir=${WGPKG_DIR}`;
|
||||
})
|
||||
.join("\n");
|
||||
|
||||
await $`echo ${inputContent} | aria2c -j ${urls.length} -x 2 -s 2 -i -`;
|
||||
|
||||
const firstChunk = `${WGPKG_DIR}/${urls[0].split("/").pop()!}`;
|
||||
await $`7z x "${firstChunk}" -o${dir} -y`;
|
||||
|
||||
await rm(WGPKG_DIR, { recursive: true });
|
||||
} else {
|
||||
throw new Error(`Unknown provider: ${provider}`);
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
export interface QuickGitHubRelease {
|
||||
assets: Asset[];
|
||||
}
|
||||
|
||||
interface Asset {
|
||||
name: string;
|
||||
browser_download_url: string;
|
||||
}
|
||||
@@ -1,319 +0,0 @@
|
||||
import {
|
||||
availableProvisions,
|
||||
createDefaultProvisions,
|
||||
createDefaultSkills,
|
||||
fetchConsumableDefinitions,
|
||||
fetchEquipmentDefinitions,
|
||||
fetchModelDefinitions,
|
||||
fetchProvisionDefinitions,
|
||||
fetchSkillDefinitions,
|
||||
fetchTankDefinitions,
|
||||
TankDefinition,
|
||||
tankIcon,
|
||||
} from "@blitzkit/core";
|
||||
import { checkConsumableProvisionInclusivity } from "@blitzkit/core/src/blitzkit/checkConsumableProvisionInclusivity";
|
||||
import strings from "@blitzkit/i18n/strings/en.json";
|
||||
import { writeFile } from "fs/promises";
|
||||
import { isEqual } from "lodash-es";
|
||||
import { tankCharacteristics } from "../../website/src/core/blitzkit/tankCharacteristics";
|
||||
import { genericDefaultEquipmentMatrix } from "../../website/src/stores/duel/constants";
|
||||
|
||||
const domain = "https://opentest.blitzkit.app";
|
||||
|
||||
import.meta.env.PUBLIC_ASSET_BASE = "https://blitzkit.github.io/assets";
|
||||
const currentTankDefinitions = await fetchTankDefinitions();
|
||||
const currentConsumableDefinitions = await fetchConsumableDefinitions();
|
||||
const currentProvisionDefinitions = await fetchProvisionDefinitions();
|
||||
const currentEquipmentDefinitions = await fetchEquipmentDefinitions();
|
||||
const currentSkillDefinitions = await fetchSkillDefinitions();
|
||||
const currentModelDefinitions = await fetchModelDefinitions();
|
||||
|
||||
import.meta.env.PUBLIC_ASSET_BASE = "https://blitzkit.github.io/assets-preview";
|
||||
const previewTankDefinitions = await fetchTankDefinitions();
|
||||
const previewConsumableDefinitions = await fetchConsumableDefinitions();
|
||||
const previewProvisionDefinitions = await fetchProvisionDefinitions();
|
||||
const previewEquipmentDefinitions = await fetchEquipmentDefinitions();
|
||||
const previewSkillDefinitions = await fetchSkillDefinitions();
|
||||
const previewModelDefinitions = await fetchModelDefinitions();
|
||||
|
||||
let notes = "# BlitzKit OpenTest Patch Notes\n\n";
|
||||
|
||||
const newTanks: TankDefinition[] = [];
|
||||
|
||||
for (const id in previewTankDefinitions.tanks) {
|
||||
if (!(id in currentTankDefinitions.tanks)) {
|
||||
newTanks.push(previewTankDefinitions.tanks[id]);
|
||||
}
|
||||
}
|
||||
|
||||
newTanks.sort((a, b) => b.tier - a.tier);
|
||||
|
||||
import.meta.env.PUBLIC_ASSET_BASE = "https://blitzkit.github.io/assets-preview";
|
||||
if (newTanks.length > 0) {
|
||||
notes += "## New Tanks\n\n";
|
||||
|
||||
for (const tank of newTanks) {
|
||||
notes += `### [${tank.name!.locales.en}](${domain}/tanks/${tank.slug})\n`;
|
||||
notes += `})\n\n`;
|
||||
}
|
||||
|
||||
notes += "\n";
|
||||
}
|
||||
|
||||
const changedTanks: [TankDefinition, TankDefinition][] = [];
|
||||
|
||||
for (const stringId in previewTankDefinitions.tanks) {
|
||||
const id = Number(stringId);
|
||||
|
||||
if (newTanks.some((tank) => tank.id === id)) continue;
|
||||
|
||||
const current = currentTankDefinitions.tanks[id];
|
||||
const preview = previewTankDefinitions.tanks[id];
|
||||
|
||||
if (isEqual(current, preview)) continue;
|
||||
|
||||
changedTanks.push([current, preview]);
|
||||
}
|
||||
|
||||
changedTanks.sort((a, b) => b[1].tier - a[1].tier);
|
||||
|
||||
import.meta.env.PUBLIC_ASSET_BASE = "https://blitzkit.github.io/assets";
|
||||
if (changedTanks.length > 0) {
|
||||
notes += "## Changed Tanks\n\n";
|
||||
|
||||
for (const [current, preview] of changedTanks) {
|
||||
const currentTurret = current.turrets.at(-1)!;
|
||||
const previewTurret = preview.turrets.at(-1)!;
|
||||
const currentGun = currentTurret.guns.at(-1)!;
|
||||
const previewGun = previewTurret.guns.at(-1)!;
|
||||
const currentShell = currentGun.shells[0];
|
||||
const previewShell = previewGun.shells[0];
|
||||
const currentEngine = current.engines.at(-1)!;
|
||||
const previewEngine = preview.engines.at(-1)!;
|
||||
const currentTracks = current.tracks.at(-1)!;
|
||||
const previewTracks = preview.tracks.at(-1)!;
|
||||
const currentTankModel = currentModelDefinitions.models[current.id];
|
||||
const previewTankModel = previewModelDefinitions.models[preview.id];
|
||||
|
||||
const currentConsumables = Object.values(
|
||||
currentConsumableDefinitions.consumables,
|
||||
).filter((consumable) =>
|
||||
checkConsumableProvisionInclusivity(consumable, current, currentGun),
|
||||
);
|
||||
const previewConsumables = Object.values(
|
||||
previewConsumableDefinitions.consumables,
|
||||
).filter((consumable) =>
|
||||
checkConsumableProvisionInclusivity(consumable, preview, previewGun),
|
||||
);
|
||||
const addedConsumables = previewConsumables.filter(
|
||||
(previewConsumable) =>
|
||||
!currentConsumables.some(
|
||||
(currentConsumable) => currentConsumable.id === previewConsumable.id,
|
||||
),
|
||||
);
|
||||
const removedConsumables = currentConsumables.filter(
|
||||
(currentConsumable) =>
|
||||
!previewConsumables.some(
|
||||
(previewConsumable) => previewConsumable.id === currentConsumable.id,
|
||||
),
|
||||
);
|
||||
|
||||
const currentProvisions = availableProvisions(
|
||||
current,
|
||||
currentGun,
|
||||
currentProvisionDefinitions,
|
||||
);
|
||||
const previewProvisions = availableProvisions(
|
||||
preview,
|
||||
previewGun,
|
||||
previewProvisionDefinitions,
|
||||
);
|
||||
const addedProvisions = previewProvisions.filter(
|
||||
(previewProvision) =>
|
||||
!currentProvisions.some(
|
||||
(currentProvision) => currentProvision.id === previewProvision.id,
|
||||
),
|
||||
);
|
||||
const removedProvisions = currentProvisions.filter(
|
||||
(currentProvision) =>
|
||||
!previewProvisions.some(
|
||||
(previewProvision) => previewProvision.id === currentProvision.id,
|
||||
),
|
||||
);
|
||||
|
||||
const currentEquipment = currentEquipmentDefinitions.presets[
|
||||
current.equipment_preset
|
||||
].slots
|
||||
.map(({ left, right }) => [left, right])
|
||||
.flat();
|
||||
const previewEquipment = previewEquipmentDefinitions.presets[
|
||||
preview.equipment_preset
|
||||
].slots
|
||||
.map(({ left, right }) => [left, right])
|
||||
.flat();
|
||||
const addedEquipment = previewEquipment
|
||||
.filter(
|
||||
(previewEquipment) =>
|
||||
!currentEquipment.some(
|
||||
(currentEquipment) => currentEquipment === previewEquipment,
|
||||
),
|
||||
)
|
||||
.map((id) => previewEquipmentDefinitions.equipments[id]);
|
||||
const removedEquipment = currentEquipment
|
||||
.filter(
|
||||
(currentEquipment) =>
|
||||
!previewEquipment.some(
|
||||
(previewEquipment) => previewEquipment === currentEquipment,
|
||||
),
|
||||
)
|
||||
.map((id) => currentEquipmentDefinitions.equipments[id]);
|
||||
|
||||
const equalize = false;
|
||||
const currentCharacteristics = tankCharacteristics(
|
||||
{
|
||||
tank: current,
|
||||
gun: currentGun,
|
||||
shell: currentShell,
|
||||
applyDynamicArmor: false,
|
||||
applyReactiveArmor: false,
|
||||
applySpallLiner: false,
|
||||
assaultDistance: 0,
|
||||
crewSkills: createDefaultSkills(currentSkillDefinitions),
|
||||
camouflage: true,
|
||||
consumables: [],
|
||||
engine: currentEngine,
|
||||
provisions: createDefaultProvisions(
|
||||
current,
|
||||
currentGun,
|
||||
currentProvisionDefinitions,
|
||||
),
|
||||
equipmentMatrix: genericDefaultEquipmentMatrix,
|
||||
stockEngine: current.engines[0],
|
||||
stockGun: current.turrets[0].guns[0],
|
||||
stockTrack: current.tracks[0],
|
||||
stockTurret: current.turrets[0],
|
||||
track: currentTracks,
|
||||
turret: currentTurret,
|
||||
equalize,
|
||||
},
|
||||
{
|
||||
equipmentDefinitions: currentEquipmentDefinitions,
|
||||
provisionDefinitions: currentProvisionDefinitions,
|
||||
tankModelDefinition: currentTankModel,
|
||||
},
|
||||
);
|
||||
const previewCharacteristics = tankCharacteristics(
|
||||
{
|
||||
tank: preview,
|
||||
gun: previewGun,
|
||||
shell: previewShell,
|
||||
applyDynamicArmor: false,
|
||||
applyReactiveArmor: false,
|
||||
applySpallLiner: false,
|
||||
assaultDistance: 0,
|
||||
crewSkills: createDefaultSkills(previewSkillDefinitions),
|
||||
camouflage: true,
|
||||
consumables: [],
|
||||
engine: previewEngine,
|
||||
provisions: createDefaultProvisions(
|
||||
preview,
|
||||
previewGun,
|
||||
previewProvisionDefinitions,
|
||||
),
|
||||
equipmentMatrix: genericDefaultEquipmentMatrix,
|
||||
stockEngine: preview.engines[0],
|
||||
stockGun: preview.turrets[0].guns[0],
|
||||
stockTrack: preview.tracks[0],
|
||||
stockTurret: preview.turrets[0],
|
||||
track: previewTracks,
|
||||
turret: previewTurret,
|
||||
equalize,
|
||||
},
|
||||
{
|
||||
equipmentDefinitions: previewEquipmentDefinitions,
|
||||
provisionDefinitions: previewProvisionDefinitions,
|
||||
tankModelDefinition: previewTankModel,
|
||||
},
|
||||
);
|
||||
const changedCharacteristics: string[] = [];
|
||||
|
||||
for (const key in currentCharacteristics) {
|
||||
const characteristicKey = key as keyof typeof currentCharacteristics;
|
||||
if (
|
||||
currentCharacteristics[characteristicKey] !==
|
||||
previewCharacteristics[characteristicKey]
|
||||
) {
|
||||
changedCharacteristics.push(characteristicKey);
|
||||
}
|
||||
}
|
||||
|
||||
notes += `### [${preview.name!.locales.en}](${domain}/tanks/${preview.slug})\n`;
|
||||
notes += `})\n\n`;
|
||||
|
||||
if (addedConsumables.length + removedConsumables.length > 0) {
|
||||
notes += `Consumables: `;
|
||||
notes += [
|
||||
...addedConsumables.map(
|
||||
(consumable) => `🟢 ${consumable.name!.locales.en}`,
|
||||
),
|
||||
...removedConsumables.map(
|
||||
(consumable) => `🔴 ${consumable.name!.locales.en}`,
|
||||
),
|
||||
].join(", ");
|
||||
notes += `\n`;
|
||||
}
|
||||
|
||||
if (addedProvisions.length + removedProvisions.length > 0) {
|
||||
notes += `Provisions: `;
|
||||
notes += [
|
||||
...addedProvisions.map(
|
||||
(provision) => `🟢 ${provision.name!.locales.en}`,
|
||||
),
|
||||
...removedProvisions.map(
|
||||
(provision) => `🔴 ${provision.name!.locales.en}`,
|
||||
),
|
||||
].join(", ");
|
||||
notes += `\n`;
|
||||
}
|
||||
|
||||
if (addedEquipment.length + removedEquipment.length > 0) {
|
||||
notes += `-Equipment: `;
|
||||
notes += [
|
||||
...addedEquipment.map(
|
||||
(equipment) => `🟢 ${equipment.name!.locales.en}`,
|
||||
),
|
||||
...removedEquipment.map(
|
||||
(equipment) => `🔴 ${equipment.name!.locales.en}`,
|
||||
),
|
||||
].join(", ");
|
||||
notes += `\n`;
|
||||
}
|
||||
|
||||
if (changedCharacteristics.length > 0) {
|
||||
notes += `Characteristics:\n`;
|
||||
|
||||
for (const characteristicUntyped of changedCharacteristics) {
|
||||
const characteristic =
|
||||
characteristicUntyped as keyof typeof currentCharacteristics;
|
||||
const name =
|
||||
strings.website.tools.tankopedia.characteristics.values[
|
||||
characteristic
|
||||
];
|
||||
const before = currentCharacteristics[characteristic];
|
||||
const after = previewCharacteristics[characteristic];
|
||||
|
||||
notes += `- ${
|
||||
typeof before === "number" && typeof after === "number"
|
||||
? after > before
|
||||
? "⬆️"
|
||||
: "🔻"
|
||||
: "✏️"
|
||||
} ${name}: \`${
|
||||
typeof before === "number" ? before.toFixed(2) : before
|
||||
}\` → \`${typeof after === "number" ? after.toFixed(2) : after}\`\n`;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
await writeFile("../../temp/patch-notes.md", notes);
|
||||
@@ -1,50 +0,0 @@
|
||||
import { type TranslationTree } from "@blitzkit/i18n";
|
||||
import locales from "@blitzkit/i18n/locales.json";
|
||||
import { writeFile } from "fs/promises";
|
||||
|
||||
const ROOT = "@blitzkit/i18n/strings";
|
||||
const WORKING_ROOT = "../../packages/i18n/strings";
|
||||
|
||||
const defaultStrings = require(`${ROOT}/${locales.default}.json`).default;
|
||||
const nonDefaultLocales = locales.supported.filter(
|
||||
({ locale }) => locale !== locales.default
|
||||
);
|
||||
|
||||
function prune(defaultStrings: TranslationTree, strings: TranslationTree) {
|
||||
for (const key in strings) {
|
||||
if (key in defaultStrings) {
|
||||
if (typeof defaultStrings[key] === typeof strings[key]) {
|
||||
if (typeof strings[key] === "string") {
|
||||
if (
|
||||
// are equivalent regardless of %s flavor
|
||||
(defaultStrings[key] as string).replaceAll(/%s\d/g, "%s") ===
|
||||
(strings[key] as string).replaceAll(/%s\d/g, "%s") ||
|
||||
// string is empty
|
||||
strings[key] === "" ||
|
||||
// string has old flavor of %s
|
||||
strings[key].match(/%s([^\d]|$)/g) !== null
|
||||
) {
|
||||
delete strings[key];
|
||||
}
|
||||
} else {
|
||||
prune(defaultStrings[key] as TranslationTree, strings[key]);
|
||||
}
|
||||
} else {
|
||||
delete strings[key];
|
||||
}
|
||||
} else {
|
||||
delete strings[key];
|
||||
}
|
||||
}
|
||||
|
||||
return strings;
|
||||
}
|
||||
|
||||
for (const locale of nonDefaultLocales) {
|
||||
console.log(`Pruning ${locale}...`);
|
||||
|
||||
const strings = require(`${ROOT}/${locale}.json`).default;
|
||||
const pruned = prune(defaultStrings, strings);
|
||||
|
||||
writeFile(`${WORKING_ROOT}/${locale}.json`, JSON.stringify(pruned, null, 2));
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
export const IDS_API_BASE = "https://ids.blitzkit.app";
|
||||
|
||||
export const PARAMETERS = [
|
||||
"spotted",
|
||||
"hits",
|
||||
"frags",
|
||||
"wins",
|
||||
"losses",
|
||||
"capture_points",
|
||||
];
|
||||
@@ -0,0 +1,64 @@
|
||||
import { idToRegion } from "@blitzkit/core";
|
||||
import { GitObjectStorage } from "../core/blitzkit/gitObjectStorage";
|
||||
import { IdArray } from "../core/blitzkit/idArray";
|
||||
import { API_RATE } from "../discoverIds/constants";
|
||||
import { sleep, withinTimeLimit } from "../discoverIds/time";
|
||||
import { IdsManifest } from "../discoverIds/types";
|
||||
import { IDS_API_BASE } from "./constants";
|
||||
import { PerformanceManifest, QuickStatistics } from "./types";
|
||||
|
||||
const applicationId = import.meta.env.PUBLIC_WARGAMING_APPLICATION_ID;
|
||||
|
||||
const storage = await new GitObjectStorage(
|
||||
"blitzkit/data-performance",
|
||||
"../../temp/performance",
|
||||
import.meta.env.GH_TOKEN,
|
||||
).init();
|
||||
|
||||
const manifest = await storage.json<PerformanceManifest>("manifest.json");
|
||||
const idsManifest = await fetch(`${IDS_API_BASE}/manifest.json`).then(
|
||||
(response) => response.json() as Promise<IdsManifest>,
|
||||
);
|
||||
|
||||
while (withinTimeLimit()) {
|
||||
manifest.last_updated = (manifest.last_updated + 1) % idsManifest.chunks;
|
||||
|
||||
const url = `${IDS_API_BASE}/chunks/chunk-${manifest.last_updated}.dat.lz4`;
|
||||
|
||||
const response = await fetch(url);
|
||||
const buffer = await response.arrayBuffer();
|
||||
const bytes = new Uint8Array(buffer);
|
||||
|
||||
const ids = IdArray.fromCompressed(bytes);
|
||||
const size = ids.size();
|
||||
|
||||
console.log(
|
||||
`Chunk ${manifest.last_updated} contains ${size} ids, estimated to take ${(size / API_RATE / 60).toFixed(0)}min`,
|
||||
);
|
||||
|
||||
for (let i = 0; i < size; i++) {
|
||||
await sleep();
|
||||
|
||||
const id = ids.get(i);
|
||||
const domain = idToRegion(id);
|
||||
|
||||
const url = `https://api.wotblitz.${
|
||||
domain
|
||||
}/wotb/tanks/stats/?application_id=${applicationId}&account_id=${id}`;
|
||||
const response = await fetch(url);
|
||||
const json = (await response.json()) as QuickStatistics;
|
||||
|
||||
const data = json.data[id];
|
||||
|
||||
if (json.status !== "ok" || data === null) {
|
||||
console.log(`Failed player ${id}; skipping...`);
|
||||
continue;
|
||||
}
|
||||
|
||||
for (const tank of data) {
|
||||
console.log(new Date(tank.battle_life_time * 1000));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// storage.commit();
|
||||
@@ -0,0 +1,26 @@
|
||||
export type PerformanceManifest = PerformanceManifestV1;
|
||||
|
||||
interface PerformanceManifestV1 {
|
||||
version: 1;
|
||||
last_updated: number;
|
||||
}
|
||||
|
||||
export interface QuickStatistics {
|
||||
status: string;
|
||||
data: Record<string, QuickStatisticsTank[] | null>;
|
||||
}
|
||||
|
||||
interface QuickStatisticsTank {
|
||||
last_battle_time: number;
|
||||
battle_life_time: number;
|
||||
tank_id: number;
|
||||
|
||||
all: Record<string, number>;
|
||||
}
|
||||
|
||||
interface ChunkObservations {
|
||||
count: number;
|
||||
observations: Record<number, Observation>;
|
||||
}
|
||||
|
||||
interface Observation {}
|
||||
@@ -1,619 +0,0 @@
|
||||
name;maxHealthFactor;piercingPowerFactor;moduleHealthFactor;damageFactor;armorFactor
|
||||
china:Ch01_Type59;1.3;1.33;1.5;1.29;1.35
|
||||
china:Ch02_Type62;1.5;1.6;1.5;1.27;1.61
|
||||
china:Ch03_WZ-111;1.4;1.17;1.4;1.3;1.35
|
||||
china:Ch04_T34_1;1.5;1.54;1.4;1.3;1.61
|
||||
china:Ch05_T34_2;1.3;1.33;1.5;1.29;1.34
|
||||
china:Ch07_Vickers_MkE_Type_BT26;5.5;5.07;3.3;7.05;8.8
|
||||
china:Ch08_Type97_Chi_Ha;3.7;3.71;2.2;3.13;5.56
|
||||
china:Ch09_M5;2.9;2.91;1.9;2.54;3.47
|
||||
china:Ch10_IS2;1.6;1.44;1.4;1.33;1.61
|
||||
china:Ch11_110;1.4;1.17;1.4;1.29;1.35
|
||||
china:Ch12_111_1_2_3;1.2;1.02;1.4;1.17;1.14
|
||||
china:Ch14_T34_3;1.3;1.37;1.5;1.13;1.17
|
||||
china:Ch15_59_16;1.9;1.77;1.6;1.57;2.24
|
||||
china:Ch15_59_16_BP;1.9;1.7;1.6;1.56;2.24
|
||||
china:Ch16_WZ_131;1.6;1.52;1.5;1.28;1.61
|
||||
china:Ch17_WZ131_1_WZ132;1.4;1.22;1.5;1.29;1.34
|
||||
china:Ch18_WZ-120;1.1;1.09;1.4;1.11;1.17
|
||||
china:Ch20_Type58;1.9;1.88;1.5;1.57;1.86
|
||||
china:Ch21_T34;2.7;2.1;1.7;1.97;2.12
|
||||
china:Ch23_112;1.4;1.17;1.4;1.31;1.35
|
||||
china:Ch24_Type64;1.9;1.86;1.6;1.57;2.35
|
||||
china:Ch26_59_Patton;1.3;1.33;1.5;1.1;1.16
|
||||
china:Ch28_WZ_132A;1.1;1.04;1.5;1.11;1.24
|
||||
china:Ch34_WZ-131G_FT;2.1;1.57;1.4;1.51;1.73
|
||||
china:Ch34_WZ-131G_FT_BP;2.1;1.57;1.4;1.51;2.02
|
||||
china:Ch35_T-34-2G_FT;1.8;1.48;1.4;1.25;1.61
|
||||
china:Ch36_WZ-111-1G_FT;1.6;1.16;1.4;1.25;1.35
|
||||
china:Ch37_WZ-111G_FT;1.2;1.05;1.4;1.15;1.13
|
||||
china:Ch39_WZ120_1G_FT;1.6;1.16;1.4;1.24;1.35
|
||||
china:Ch40_WZ120G_FT;1.1;1.05;1.4;1.08;1.13
|
||||
china:Ch42_M41D;1.7;1.49;1.5;1.24;1.61
|
||||
china:Ch43_WZ-122_2;1.3;1.21;1.5;1.31;1.35
|
||||
china:Ch45_WZ_114;1.2;1.02;1.4;1.19;1.13
|
||||
china:Ch47_BZ_176;1.2;1.03;1.4;1.17;1.13
|
||||
china:Ch49_BZ_68;1.2;1.02;1.4;1.2;1.16
|
||||
china:Ch50_BZ_166;1.4;1.17;1.4;1.3;1.35
|
||||
china:Ch51_BZ_58;1.6;1.46;1.4;1.29;1.62
|
||||
china:Ch56_BZ_74_1;1.2;1.02;1.4;1.16;1.14
|
||||
china:Ch59_BZ58_2;1.2;1.02;1.4;1.19;1.13
|
||||
china:Ch60_Type59_spc;1.3;1.37;1.5;1.32;1.35
|
||||
china:Ch_LT_vz38;4.3;4.29;2.7;3.99;4.88
|
||||
china:Ch_WZ-112v2;1.4;1.17;1.4;1.31;1.35
|
||||
china:Type_58BP;1.9;1.88;1.5;1.57;2.04
|
||||
european:Cz02_T50;1.1;1.03;1.4;1.12;1.19
|
||||
european:Cz05_T34-100;1.5;1.45;1.4;1.29;1.61
|
||||
european:Cz07_TVP_46;1.3;1.12;1.5;1.29;1.35
|
||||
european:Cz08_T-25;1.9;1.83;1.5;1.56;2.02
|
||||
european:Cz08_T-25BP;1.9;1.83;1.5;1.55;2.02
|
||||
european:Cz08_T-25BPS;1.9;1.83;1.5;1.57;2.02
|
||||
european:Cz13_T-27;1.1;1.07;1.4;1.12;1.19
|
||||
european:Cz14_Skoda_T-56;1.4;1.17;1.4;1.33;1.35
|
||||
european:Cz15_Skoda_T-45;1.7;1.44;1.4;1.27;1.61
|
||||
european:Cz16_TNH_T_vz51;1.2;1.02;1.4;1.17;1.15
|
||||
european:Cz18_TNH_105_1000;1.4;1.16;1.4;1.28;1.35
|
||||
european:Cz19_Vz_44_1;1.7;1.43;1.4;1.3;1.61
|
||||
european:Cz20_ShPTK_TVP_100;1.5;1.16;1.4;1.24;1.34
|
||||
european:Cz29_Skoda_P-JS;2.2;1.67;1.4;1.56;1.78
|
||||
european:Cz29_Skoda_P-JS_BP;2.2;1.67;1.4;1.57;1.79
|
||||
european:F01_Vickers_MkF;5.5;5.07;3.3;6.16;8.8
|
||||
european:It09_P43_ter;1.5;1.54;1.4;1.3;1.61
|
||||
european:It10_P43_BD;1.9;1.74;1.5;1.57;1.82
|
||||
european:It10_P43_bis;1.9;1.74;1.5;1.57;1.82
|
||||
european:It10_P43_bis_BP;1.9;1.7;1.5;1.58;1.82
|
||||
european:It116_Carro_d_assalto_P88;1.6;1.33;1.4;1.28;1.61
|
||||
european:It117_ProgettoCC55mod54;1.3;1.13;1.4;1.29;1.35
|
||||
european:It119_ProgettoC50mod66;1.1;1.02;1.4;1.18;1.13
|
||||
european:It12_Prototipo_Standard_B;1.1;1.04;1.4;1.14;1.17
|
||||
european:It13_Progetto_M35_mod_46;1.3;1.33;1.5;1.27;1.35
|
||||
european:It14_P44_Pantera;1.3;1.21;1.5;1.26;1.35
|
||||
european:It15_Semovente_M41;3.2;1.98;1.5;1.97;2.13
|
||||
european:It16_Bassoto;2;1.59;1.4;1.53;1.8
|
||||
european:It17_Semovente_mod_56;1.7;1.4;1.4;1.28;1.62
|
||||
european:It18_Semovente_mod_64;1.4;1.2;1.4;1.24;1.35
|
||||
european:It19_Controcarro_1MK2_Ciclope;1.1;1.05;1.4;1.19;1.13
|
||||
european:It22_Progetto_C45_mod_71;1.3;1.14;1.4;1.23;1.35
|
||||
european:It30_CC_mod_64_Prem;1.4;1.17;1.4;1.25;1.35
|
||||
european:Pl03_PzV_Pudel;1.9;1.57;1.5;1.56;1.92
|
||||
european:Pl05_50TP_Tyszkiewicza;1.2;1.02;1.4;1.18;1.13
|
||||
european:Pl06_10TP;4.3;4.29;2.7;4.28;7.66
|
||||
european:Pl07_14TP;3.6;3.57;2.1;3.12;5.56
|
||||
european:Pl08_50TP_prot;1.2;1.02;1.4;1.17;1.14
|
||||
european:Pl10_40TP_Habicha;2.1;1.64;1.4;1.57;1.83
|
||||
european:Pl119_CS_52_LIS;1.5;1.56;1.4;1.31;1.61
|
||||
european:Pl11_45TP_Habicha;1.6;1.44;1.4;1.3;1.61
|
||||
european:Pl13_53TP_Markowskiego;1.4;1.14;1.4;1.32;1.35
|
||||
european:Pl17_DS_PZlnz;2.6;2.28;1.7;1.95;2.12
|
||||
european:Pl18_BUGI;1.9;1.57;1.5;1.58;1.94
|
||||
european:Pl20_CS_44;1.5;1.54;1.4;1.3;1.61
|
||||
european:Pl22_CS_59;1.1;1.04;1.4;1.1;1.21
|
||||
european:Pl23_CS_53;1.3;1.31;1.5;1.29;1.35
|
||||
european:Pl24_56TP;1.4;1.15;1.4;1.29;1.35
|
||||
european:Pl27_SDP_Wz_66T;1.5;1.17;1.4;1.27;1.35
|
||||
european:Pl28_SDP_Wz_60;1.1;1.05;1.4;1.11;1.12
|
||||
european:Pl30_SDP_Wz58T;1.4;1.16;1.4;1.26;1.35
|
||||
european:Pl31_SDP_Wz_57D;1.7;1.43;1.4;1.28;1.62
|
||||
european:Pl32_SDP_Wz_44;2;1.57;1.4;1.52;1.76
|
||||
european:Pl33_SDP_Wz_40;3.2;2.13;1.5;1.96;2.13
|
||||
european:S02_StrvM42;2.7;2.22;1.7;1.95;2.11
|
||||
european:S04_Lago-I;3.1;2.69;1.9;2.54;2.32
|
||||
european:S07_Strv74BP;1.9;1.67;1.5;1.55;1.9
|
||||
european:S07_Strv_74;1.9;1.67;1.5;1.55;1.9
|
||||
european:S13_Leo;1.5;1.58;1.4;1.3;1.61
|
||||
european:S13_Leo_NY;1.5;1.58;1.4;1.3;1.61
|
||||
european:S17_EMIL_1952E2;1.2;1.02;1.4;1.16;1.12
|
||||
european:S18_EMIL_1951E1;1.3;1.16;1.4;1.29;1.35
|
||||
european:S23_Strv_81;1.3;1.14;1.5;1.26;1.35
|
||||
european:S25_EMIL_51;1.3;1.12;1.4;1.29;1.35
|
||||
european:S26_Lancen_C;1.3;1.22;1.5;1.31;1.35
|
||||
european:S32_Bofors_Tornvagn;1.1;1.02;1.4;1.17;1.12
|
||||
france:AMX38;4.4;4.29;2.7;4.15;5.95
|
||||
france:AMX40;3;2.88;1.9;2.52;3.53
|
||||
france:AMX50_Foch;1.2;1.05;1.4;1.11;1.14
|
||||
france:AMX_12t;1.9;1.64;1.6;1.6;2.02
|
||||
france:AMX_13_75;1.7;1.61;1.5;1.25;1.61
|
||||
france:AMX_13_90;1.4;1.37;1.5;1.29;1.34
|
||||
france:AMX_50_100;1.4;1.12;1.4;1.26;1.35
|
||||
france:AMX_50_120;1.2;1.02;1.4;1.12;1.17
|
||||
france:AMX_AC_Mle1946;1.7;1.45;1.4;1.24;1.61
|
||||
france:AMX_AC_Mle1948;1.5;1.16;1.4;1.24;1.35
|
||||
france:AMX_M4_1945;1.6;1.47;1.4;1.28;1.61
|
||||
france:ARL_44;2.1;1.57;1.4;1.53;1.82
|
||||
france:ARL_44BP;2.1;1.53;1.4;1.58;1.81
|
||||
france:ARL_V39;2;1.59;1.4;1.52;1.82
|
||||
france:Achilles_FR;2.1;1.6;1.4;1.52;1.83
|
||||
france:B1;4.1;2.8;1.6;2.54;3.64
|
||||
france:BDR_G1B;3.2;1.91;1.5;1.95;2.13
|
||||
france:Bat-Chat-25CL;1.1;1.05;1.5;1.1;1.22
|
||||
france:D1;4.3;4.62;2.7;3.8;6.52
|
||||
france:D2;3.7;3.64;2.2;3;5.52
|
||||
france:ELC_AMX;2.8;1.97;2.3;2.31;2.09
|
||||
france:F113_PzV_FR;1.9;1.65;1.5;1.56;1.89
|
||||
france:F114_Projet_4_1;1.1;1.03;1.4;1.09;1.22
|
||||
france:F115_Lorraine_50t;1.2;1.02;1.4;1.13;1.16
|
||||
france:F116_Bat_Chat_Bourrasque;1.3;1.28;1.5;1.31;1.34
|
||||
france:F117_Alt_Proto_AMX_30;1.3;1.15;1.5;1.29;1.35
|
||||
france:F11_Renault_G1R;3.2;2;1.5;1.96;2.12
|
||||
france:F120_Project_Louis;1.1;1.04;1.4;1.12;1.14
|
||||
france:F123_ERAC_105_Proto;1.3;1.22;1.5;1.3;1.35
|
||||
france:F126_AMX_13_M24;1.5;1.58;1.4;1.32;1.62
|
||||
france:F127_ELC_AMX_901_Proto;1.4;1.28;1.5;1.28;1.34
|
||||
france:F140_Sentinelle;1.4;1.15;1.4;1.28;1.35
|
||||
france:F19_Lorraine40t;1.3;1.17;1.5;1.3;1.34
|
||||
france:F19_Lorraine40t_Com;1.3;1.17;1.5;1.29;1.34
|
||||
france:F34_ARL_V39_BP;2.1;1.59;1.4;1.51;1.82
|
||||
france:F68_AMX_Chasseur_de_char_46;1.3;1.17;1.5;1.25;1.33
|
||||
france:F69_AMX_13D;1.4;1.16;1.5;1.28;1.34
|
||||
france:F69_AMX_13_57GF;1.6;1.49;1.5;1.26;1.61
|
||||
france:F71_AMX_30_prototype;1.1;1.06;1.4;1.12;1.19
|
||||
france:F73_M4A1_Revalorise;1.3;1.23;1.5;1.27;1.34
|
||||
france:F74_AMX_M4_1949;1.4;1.12;1.4;1.28;1.35
|
||||
france:F75_Char_de_25t;1.1;1.02;1.5;1.11;1.22
|
||||
france:F84_Somua_SM;1.4;1.12;1.4;1.14;1.14
|
||||
france:F89_Canon_dassaut_105;1.6;1.15;1.4;1.26;1.35
|
||||
france:FCM_36Pak40;4.2;2.95;1.9;3.18;5.52
|
||||
france:FCM_50t;1.3;1.17;1.5;1.25;1.35
|
||||
france:F_AMX-12BP;1.9;1.64;1.6;1.6;2.02
|
||||
france:RenaultFT_AC;5.5;4.37;2.2;4.49;8.51
|
||||
france:RenaultR35;5.5;5.28;3.3;6.76;7.8
|
||||
france:RenaultUE57;4.2;2.79;1.9;2.68;5.95
|
||||
france:S_35CA;3.2;2.07;1.5;1.96;2.11
|
||||
france:Somua_Sau_40;3.7;2.75;1.8;2.54;3.62
|
||||
germany:B-1bis_captured;4.1;2.96;1.6;2.55;3.89
|
||||
germany:DW_II;3.7;2.52;1.6;2.52;3.53
|
||||
germany:DickerMax;2.1;1.57;1.4;1.53;2.02
|
||||
germany:E-25;1.8;1.46;1.4;1.24;1.61
|
||||
germany:E-50;1.1;1.09;1.4;1.1;1.15
|
||||
germany:E-75;1.2;1.02;1.4;1.17;1.14
|
||||
germany:Ferdinand;1.4;1.16;1.4;1.25;1.35
|
||||
germany:G100_Gtraktor_Krupp;4.9;3.31;1.9;3.49;5.75
|
||||
germany:G103_RU_251;1.4;1.3;1.5;1.25;1.33
|
||||
germany:G106_PzKpfwPanther_AusfF;1.3;1.21;1.5;1.26;1.35
|
||||
germany:G109_Steyr_WT;1.8;1.37;1.4;1.27;1.6
|
||||
germany:G110_Mauschen;1.2;1.02;1.4;1.18;1.12
|
||||
germany:G112_JagdPanzer_105;1.2;1.05;1.4;1.04;1.18
|
||||
germany:G113_SP_I_C;1.7;1.49;1.5;1.28;1.58
|
||||
germany:G114_Rheinmetall_Scorpion;1.6;1.16;1.4;1.24;1.33
|
||||
germany:G115_VK10001P;1.4;1.15;1.4;1.33;1.35
|
||||
germany:G118_VK4503;1.7;1.3;1.4;1.27;1.61
|
||||
germany:G119_Panzer58_SH;1.3;1.22;1.5;1.28;1.35
|
||||
germany:G119_Pz58_Mutz;1.3;1.17;1.5;1.26;1.35
|
||||
germany:G120_M41_90;1.4;1.29;1.5;1.26;1.34
|
||||
germany:G126_HWK_12;1.1;1.05;1.5;1.08;1.29
|
||||
germany:G136_Tiger_131;2.1;1.68;1.4;1.55;1.85
|
||||
germany:G138_VK16801P;1.5;1.15;1.4;1.16;1.13
|
||||
germany:G140_HWK_30;1.4;1.27;1.5;1.27;1.34
|
||||
germany:G142_M48RPz;1.3;1.18;1.5;1.27;1.35
|
||||
germany:G147_mPanzer_64;1.7;1.49;1.5;1.29;1.61
|
||||
germany:G148_Elephant;1.4;1.16;1.4;1.21;1.35
|
||||
germany:G154_Kpz_07_RH;1.3;1.15;1.5;1.26;1.35
|
||||
germany:G162_Project_Kpz_07P_E;1.1;1.02;1.4;1.16;1.14
|
||||
germany:G164_Kpz_Pr_68_P;1.3;1.22;1.5;1.3;1.34
|
||||
germany:G165_Erich_Koncept;1.1;1.06;1.4;1.14;1.19
|
||||
germany:G166_LKpz_70_K;1.1;1.02;1.5;1.11;1.32
|
||||
germany:G167_Tiger_Maus;1.2;1.03;1.4;1.11;1.13
|
||||
germany:G168_KJpz_T_III;1.2;1.05;1.4;1.05;1.29
|
||||
germany:G190_VK_1602_Quby;1.4;1.36;1.5;1.25;1.34
|
||||
germany:G20_Marder_II;4.2;3.01;1.9;3.18;5.54
|
||||
germany:G85_Auf_Panther;1.5;1.49;1.5;1.25;1.61
|
||||
germany:G_E-75RT;1.4;1.14;1.4;1.3;1.35
|
||||
germany:G_E-75TS;1.2;1.03;1.4;1.13;1.13
|
||||
germany:G_VK3502_BP;2.1;1.68;1.4;1.57;1.79
|
||||
germany:H39_captured;4.3;5.58;2.7;3.99;6.04
|
||||
germany:Hetzer;3.7;2.6;1.8;2.54;3.47
|
||||
germany:Indien_Panzer;1.3;1.17;1.5;1.25;1.35
|
||||
germany:JagdPanther;1.8;1.37;1.4;1.25;1.62
|
||||
germany:JagdPantherII;1.6;1.16;1.4;1.23;1.35
|
||||
germany:JagdPzIV;2.1;1.58;1.4;1.49;1.8
|
||||
germany:JagdPzIV_AusfBP;2;1.58;1.4;1.49;1.8
|
||||
germany:JagdTiger;1.1;1.05;1.4;1.04;1.12
|
||||
germany:JagdTiger_SdKfz_185;1.4;1.17;1.4;1.21;1.35
|
||||
germany:JagdTiger_SdKfz_185_Snowstorm;1.4;1.33;1.4;1.21;1.35
|
||||
germany:Krupp-38D;2.6;2.22;1.7;1.95;2.12
|
||||
germany:Lowe;1.4;1.11;1.4;1.29;1.35
|
||||
germany:Nashorn;2;1.51;1.4;1.51;2.24
|
||||
germany:Nashorn_BP;2;1.51;1.4;1.5;2.24
|
||||
germany:Panther_II;1.3;1.21;1.5;1.26;1.35
|
||||
germany:Panther_M10;1.5;1.54;1.4;1.26;1.61
|
||||
germany:PanzerJager_I;5.5;4.33;2.2;4.49;8.8
|
||||
germany:Pro_Ag_A;1.1;1.02;1.4;1.1;1.21
|
||||
germany:Pz35t;4.4;4.9;2.7;3.94;6.05
|
||||
germany:Pz38_NA;2.9;2.78;1.9;2.55;3.65
|
||||
germany:Pz38t;3.6;3.88;2.1;3.05;5.58
|
||||
germany:PzII;5.5;5.28;3.3;6.67;6.81
|
||||
germany:PzIII;3.7;3.69;2.2;3.26;5.49
|
||||
germany:PzIII_A;3.7;3.09;2.1;2.98;5.58
|
||||
germany:PzIII_IV;2.7;2.22;1.7;1.95;2.12
|
||||
germany:PzII_J;3.6;5.5;2.1;2.83;5.46
|
||||
germany:PzII_Luchs;2.9;2.94;1.9;2.55;2.2
|
||||
germany:PzIV;2.7;2.22;1.7;1.95;2.13
|
||||
germany:PzIV_Hydro;2.5;2.22;1.7;1.95;2.11
|
||||
germany:PzIV_schmalturm;1.9;1.65;1.5;1.53;1.87
|
||||
germany:PzV;1.5;1.33;1.4;1.26;1.61
|
||||
germany:PzVI;1.7;1.3;1.4;1.28;1.62
|
||||
germany:PzVIB_Tiger_II;1.4;1.14;1.4;1.27;1.35
|
||||
germany:PzVI_AusfBP;2.1;1.68;1.4;1.56;1.79
|
||||
germany:PzVI_Tiger_P;1.7;1.3;1.4;1.28;1.62
|
||||
germany:PzV_PzIV;2.6;2.22;1.7;1.95;2.12
|
||||
germany:Pz_II_AusfG;3.8;2.9;2.1;2.85;5.55
|
||||
germany:Pz_IV_AusfA;3.6;3.2;2.2;4.05;5.74
|
||||
germany:Pz_IV_AusfBT;2.7;2.53;1.7;1.96;2.12
|
||||
germany:Pz_IV_AusfD;3.1;2.43;1.9;2.54;3.09
|
||||
germany:Pz_Sfl_IVc;3;1.61;1.5;1.98;2.08
|
||||
germany:RhB_Waffentrager;1.6;1.26;1.4;1.28;1.33
|
||||
germany:S01_Frankentank;1.7;1.33;1.4;1.37;1.62
|
||||
germany:S35_captured;3.8;2.85;2.1;2.93;5.52
|
||||
germany:StuGIII;3.2;1.93;1.5;1.97;2.12
|
||||
germany:Sturer_Emil;1.8;1.31;1.4;1.28;1.61
|
||||
germany:T-15;3.8;4.72;2.1;2.82;5.55
|
||||
germany:T-25;2.5;2.13;1.7;1.95;2.11
|
||||
germany:VK1602;2.8;2.9;2.3;1.96;2.11
|
||||
germany:VK2801;1.9;1.53;1.6;1.58;1.95
|
||||
germany:VK2801_BP;1.9;1.53;1.6;1.59;1.95
|
||||
germany:VK3001H;3.2;1.75;1.5;1.96;2.13
|
||||
germany:VK3001P;1.9;1.61;1.5;1.57;1.81
|
||||
germany:VK3002DB;1.5;1.58;1.4;1.28;1.61
|
||||
germany:VK3002DB_BP;1.9;1.65;1.5;1.56;1.87
|
||||
germany:VK3002DB_V1;1.9;1.65;1.5;1.56;1.84
|
||||
germany:VK3002M;1.9;1.65;1.5;1.57;1.91
|
||||
germany:VK3601H;2.1;1.64;1.4;1.57;1.78
|
||||
germany:VK4502A;1.3;1.17;1.4;1.29;1.35
|
||||
germany:VK4502P;1.2;1.02;1.4;1.18;1.13
|
||||
germany:Waffentrager_IV;1.2;1.06;1.4;1.12;1.19
|
||||
germany:Waffentrager_IV_CL;1.2;1.05;1.4;1.06;1.19
|
||||
japan:Chi_Ha;3.6;3.8;2.2;3.2;5.54
|
||||
japan:Chi_He;3;2.72;1.9;2.55;3.24
|
||||
japan:Chi_Ni;4.4;4.62;2.5;4.09;6.52
|
||||
japan:Chi_Nu;2.6;2.02;1.7;1.94;2.12
|
||||
japan:Chi_Nu_Kai;2.6;2.02;1.7;1.95;2.11
|
||||
japan:Chi_Ri;1.5;1.58;1.4;1.25;1.61
|
||||
japan:Chi_To;1.9;1.61;1.5;1.55;1.9
|
||||
japan:Firefly_GuP;1.9;1.49;1.5;1.55;2.01
|
||||
japan:G09_Hetzer_GuP;3.7;2.6;1.8;2.54;3.47
|
||||
japan:Ha_Go;5.7;5.36;3.3;5.99;8.2
|
||||
japan:IS-2_GuP;1.6;1.44;1.4;1.33;1.61
|
||||
japan:J21_Ho_Ri;1.2;1.05;1.4;1.11;1.13
|
||||
japan:J22_Ho_Ri_type96;1.5;1.16;1.4;1.25;1.35
|
||||
japan:J23_Chi_To_SPG;1.8;1.37;1.4;1.25;1.62
|
||||
japan:J24_Type_57;1.4;1.16;1.4;1.33;1.35
|
||||
japan:J26_Type_68;1.2;1.02;1.4;1.13;1.13
|
||||
japan:J27_Chi_Se;1.4;1.15;1.4;1.27;1.35
|
||||
japan:J28_Ju_To;1.7;1.41;1.4;1.32;1.62
|
||||
japan:J29_Ju_Nu;2.1;1.73;1.4;1.57;1.8
|
||||
japan:J29_Ju_Nu_BP;2.1;1.73;1.4;1.57;1.8
|
||||
japan:J30_Mitsu_108;3.2;2.37;1.5;1.97;2.13
|
||||
japan:J31_Type_5_Ka_Ri;1.5;1.16;1.4;1.26;1.35
|
||||
japan:J36_Type_63_HT;1.4;1.15;1.4;1.29;1.35
|
||||
japan:J38_Type_95_Ji_Ro;1.5;1.16;1.4;1.22;1.35
|
||||
japan:Ke_Ho;2.9;2.71;1.9;2.55;1
|
||||
japan:Ke_Ni;3.8;4.07;2.1;2.67;5.71
|
||||
japan:Ke_Ni_B;4.5;4.85;2.1;2.14;5.71
|
||||
japan:PzVI_GuP;2.1;1.64;1.4;1.54;1.81
|
||||
japan:Pz_IV_AusfH;2.6;2.22;1.7;1.95;2.12
|
||||
japan:STA_1;1.3;1.15;1.5;1.28;1.34
|
||||
japan:Type_61;1.1;1.02;1.4;1.1;1.24
|
||||
other:AMX_dracula;1.5;1.58;1.4;1.3;1.61
|
||||
other:Akawara;1.3;1.28;1.5;1.28;1.35
|
||||
other:Oth06_Sega_Lupus;1.7;1.44;1.4;1.34;1.62
|
||||
other:Oth08_WH_Vindicator;1.8;1.74;1.4;1.24;1.61
|
||||
other:Oth09_WH_Predator;1.7;1.47;1.4;1.25;1.62
|
||||
other:Oth11_T-55A;1.1;1.1;1.4;1.09;1.16
|
||||
other:Oth12_Sega_Hafen;1.6;1.66;1.4;1.27;1.61
|
||||
other:Oth14_MdM_AshKnight;1.7;1.47;1.4;1.27;1.62
|
||||
other:Oth15_RustCrab;2.6;2.22;1.7;1.96;2.12
|
||||
other:Oth16_KV_TG;1.6;1.76;1.4;1.27;1.61
|
||||
other:Oth17_BDT-5A;2.6;2.22;1.7;1.95;2.12
|
||||
other:Oth18_BDT-5B;1.9;1.85;1.5;1.55;1.94
|
||||
other:Oth19_BDT-5C;1.5;1.66;1.4;1.25;1.61
|
||||
other:Oth20_M4FL10;1.5;1.67;1.4;1.27;1.61
|
||||
other:Oth22_Sega_Vulcan;1.7;1.41;1.4;1.33;1.62
|
||||
other:Oth23_Werewolf;1.6;1.44;1.4;1.33;1.61
|
||||
other:Oth24_StuH_42HW;3.2;2.6;1.5;1.97;2.13
|
||||
other:Oth25_HWT20_FalconFire;1.7;1.47;1.4;1.25;1.62
|
||||
other:Oth26_StrvM42HW;2.7;2.22;1.7;1.96;2.11
|
||||
other:Oth27_M24_AMX;1.9;1.64;1.6;1.6;2.02
|
||||
other:Oth28_Sturmfeur_HW;1.7;1.41;1.4;1.31;1.61
|
||||
other:Oth29_A15HW;2.8;1.83;2.3;1.96;2.12
|
||||
other:Oth30_T54MS;1.3;1.2;1.5;1.3;1.35
|
||||
other:Oth31_T150BP;2.1;1.71;1.4;1.56;1.79
|
||||
other:Oth33_Blizzard_BP;2;1.68;1.6;1.56;2.21
|
||||
other:Oth34_PanzerMummy;1.7;1.39;1.4;1.3;1.61
|
||||
other:Oth35_PanzerMejai;3.2;2.27;1.5;1.95;2.13
|
||||
other:Oth36_Indien_Panzer_S1;1.5;1.56;1.4;1.28;1.61
|
||||
other:Oth37_T26_E4_SuperPershing_S1;1.3;1.25;1.5;1.3;1.35
|
||||
other:Oth38_50TP_Tyszkiewicza_S1;1.1;1.02;1.4;1.17;1.14
|
||||
other:Oth39_T20_S2;1.5;1.62;1.4;1.28;1.61
|
||||
other:Oth40_TVP_46_S2;1.3;1.15;1.5;1.28;1.35
|
||||
other:Oth41_Centurion_Mk3_S2;1.1;1.05;1.4;1.11;1.18
|
||||
other:Oth42_ForestWitch_HW23;1.7;1.42;1.4;1.32;1.61
|
||||
other:Oth44_Charioteer_T;1.6;1.17;1.4;1.27;1.35
|
||||
other:Oth45_Sandstriker;1.4;1.16;1.4;1.33;1.35
|
||||
other:Oth46_Charioteer_S3;1.8;1.37;1.4;1.27;1.61
|
||||
other:Oth47_AMX_13_90_S3;1.4;1.3;1.5;1.28;1.34
|
||||
other:Oth48_EMIL_1951E1_S3;1.1;1.02;1.4;1.15;1.14
|
||||
other:Oth49_TM_04_NT;1.5;1.63;1.4;1.34;1.61
|
||||
other:Oth50_STT;1.6;1.55;1.5;1.28;1.61
|
||||
other:Oth51_FD_24;1.3;1.18;1.5;1.28;1.35
|
||||
other:Oth52_Toxique;1.3;1.32;1.5;1.31;1.35
|
||||
other:Oth53_Rammer;1.6;1.46;1.4;1.31;1.61
|
||||
other:Oth61_Pz_VM_Set;4.1;2.58;1.6;2.54;3.71
|
||||
other:Oth62_Pz_VlD_Set;3.2;1.97;1.5;1.96;2.13
|
||||
other:Oth63_Pz_VllF_Set;2.1;1.64;1.4;1.57;1.84
|
||||
other:Oth64_Pz_VlllK_Set;1.6;1.44;1.4;1.31;1.61
|
||||
other:Oth65_PzVIllM_Tigeom;2.1;1.67;1.4;1.59;1.86
|
||||
other:Oth66_E100ANN_S4;1.7;1.47;1.4;1.33;1.62
|
||||
other:Oth67_FV215b_183ANN_S4;1.5;1.16;1.4;1.24;1.35
|
||||
other:Oth68_KV2ANN_S4;1.2;1.03;1.4;1.23;1.14
|
||||
other:Oth69_Souleater;1.5;1.17;1.4;1.26;1.35
|
||||
other:Oth70_Lightbringer;1.6;1.47;1.4;1.29;1.61
|
||||
other:Oth71_Titan_Strife;1.3;1.16;1.4;1.28;1.35
|
||||
other:Oth72_Hazard_I;1.5;1.57;1.4;1.3;1.61
|
||||
other:Oth73_Nemini;1.4;1.17;1.4;1.31;1.35
|
||||
other:Oth74_Argonaut;1.1;1.05;1.4;1.06;1.18
|
||||
other:Oth75_Braniaq_DM5;1.1;1.06;1.4;1.14;1.18
|
||||
other:Oth76_Destiny;1.2;1.02;1.4;1.17;1.15
|
||||
other:Oth77_Prowler;1.4;1.16;1.4;1.3;1.35
|
||||
other:Oth78_AC_17_P_Sterope;1.2;1.02;1.4;1.13;1.12
|
||||
other:Oth80_AC_16_Celeno;1.2;1.02;1.4;1.13;1.12
|
||||
other:Oth81_AC_15_Taygete;1.4;1.24;1.4;1.33;1.35
|
||||
other:Oth82_AC_14_Pleione;1.4;1.15;1.4;1.29;1.35
|
||||
other:Oth83_AC_13_Merope;1.7;1.4;1.4;1.32;1.61
|
||||
other:Oth84_FVE_Defender;1.1;1.12;1.4;1.16;1.15
|
||||
other:Oth85_Ghoul;1.3;1.36;1.5;1.28;1.35
|
||||
other:Oth86_Survivalist;1.1;1.06;1.4;1.1;1.12
|
||||
other:Oth92_JagdPantherII_Titan;1.4;1.17;1.4;1.24;1.35
|
||||
other:Oth93_Convoyer;1.4;1.16;1.4;1.24;1.35
|
||||
other:Sega_Edelweiss;1.5;1.62;1.4;1.28;1.61
|
||||
other:Sega_Nameless;1.7;1.41;1.4;1.29;1.62
|
||||
other:Strv_74A2;1.9;1.8;1.5;1.54;1.9
|
||||
other:Van_Helsing;1.8;1.59;1.4;1.25;1.61
|
||||
other:WZ-135G_FT;1.8;1.5;1.4;1.3;1.61
|
||||
uk:GB03_Cruiser_Mk_I;4.4;4.9;2.7;3.96;9.12
|
||||
uk:GB04_Valentine;2.9;1.85;1.9;2.53;3.37
|
||||
uk:GB05_Vickers_Medium_Mk_II;6.5;3.84;2.2;3.8;12.37
|
||||
uk:GB06_Vickers_Medium_Mk_III;4.9;3.9;1.9;2.88;5.74
|
||||
uk:GB07_Matilda;4.1;2.83;1.6;2.56;3.64
|
||||
uk:GB08_Churchill_I;3.3;1.8;1.5;1.96;2.13
|
||||
uk:GB09_Churchill_VII;2.1;1.7;1.4;1.54;1.76
|
||||
uk:GB09_Churchill_VII_BP;2.1;1.67;1.4;1.54;1.79
|
||||
uk:GB101_FV1066_Senlac;1.4;1.16;1.5;1.24;1.33
|
||||
uk:GB106_Cobra;1.1;1.05;1.4;1.14;1.16
|
||||
uk:GB108_A46;1.5;1.56;1.5;1.25;1.6
|
||||
uk:GB109_GSOR_1008;1.6;1.16;1.4;1.25;1.34
|
||||
uk:GB109_GSOR_1008_Fearless;1.6;1.18;1.4;1.24;1.34
|
||||
uk:GB10_Black_Prince;1.7;1.47;1.4;1.23;1.62
|
||||
uk:GB110_FV4201_Chieftain_Prototype;1.1;1.02;1.4;1.13;1.15
|
||||
uk:GB111_Charlemagne;1.4;1.13;1.4;1.31;1.35
|
||||
uk:GB112_Caliban;1.4;1.16;1.4;1.45;1.35
|
||||
uk:GB114_Vickers_MBT_Mk3;1.3;1.28;1.5;1.12;1.14
|
||||
uk:GB116_Harry_Hopkins;2.5;1.97;2.3;1.96;2.12
|
||||
uk:GB11_Caernarvon;1.3;1.13;1.4;1.23;1.35
|
||||
uk:GB11_Caernarvon_D;1.4;1.16;1.4;1.3;1.35
|
||||
uk:GB128_Nemesis;1.3;1.29;1.5;1.28;1.35
|
||||
uk:GB12_Conqueror;1.1;1.02;1.4;1.1;1.13
|
||||
uk:GB19_Sherman_Firefly;1.9;1.49;1.5;1.55;2.01
|
||||
uk:GB20_Crusader;2.7;1.83;2.3;1.96;2.11
|
||||
uk:GB21_A27BP;1.9;1.7;1.5;1.55;1.94
|
||||
uk:GB21_Cromwell;1.9;1.7;1.5;1.55;1.94
|
||||
uk:GB22_Comet;1.5;1.58;1.4;1.25;1.61
|
||||
uk:GB23_Centurion;1.3;1.12;1.5;1.25;1.35
|
||||
uk:GB24_Centurion_Mk3;1.1;1.02;1.4;1.14;1.15
|
||||
uk:GB32_Tortoise;1.1;1.05;1.4;1.05;1.11
|
||||
uk:GB35_Sentinel_AC_IV;1.9;1.7;1.5;1.56;1.94
|
||||
uk:GB39_Universal_CarrierQF2;5.5;4.89;2.2;3.99;11.07
|
||||
uk:GB40_Gun_Carrier_BP;2;1.56;1.4;1.52;1.77
|
||||
uk:GB40_Gun_Carrier_Churchill;2.1;1.48;1.4;1.51;1.79
|
||||
uk:GB41_Challenger;1.8;1.35;1.4;1.26;1.61
|
||||
uk:GB42_Valentine_AT;4.3;2.68;1.9;2.43;5.48
|
||||
uk:GB44_Archer_Custom;3.2;1.76;1.5;1.98;2.08
|
||||
uk:GB51_Excelsior;3.2;2.27;1.5;1.97;2.13
|
||||
uk:GB52_FV201_A45;1.7;1.47;1.4;1.24;1.61
|
||||
uk:GB57_Alecto;3.7;2.93;1.8;2.54;1
|
||||
uk:GB58_Cruiser_Mk_III;4.4;4.9;2.5;4.26;6.52
|
||||
uk:GB59_Cruiser_Mk_IV;3.7;3.82;2.2;3.05;5.52
|
||||
uk:GB60_Covenanter;3;3;1.9;2.55;2.68
|
||||
uk:GB63_TOG_II;1.9;1.53;1.4;1.54;1.8
|
||||
uk:GB63_TOG_II_BP;1.9;1.53;1.4;1.57;1.79
|
||||
uk:GB68_Matilda_Black_Prince;2.5;1.96;1.7;1.98;2.12
|
||||
uk:GB69_Cruiser_Mk_II;5.9;5.88;3.3;5.32;8.2
|
||||
uk:GB71_AT_15A;1.7;1.58;1.4;1.22;1.62
|
||||
uk:GB72_AT15;1.4;1.19;1.4;1.19;1.35
|
||||
uk:GB73_AT2;3.2;2.45;1.5;1.97;2.13
|
||||
uk:GB74_AT8;2;1.6;1.4;1.51;1.76
|
||||
uk:GB75_AT7;1.7;1.33;1.4;1.23;1.62
|
||||
uk:GB76_Mk_VIC;4.3;5.58;2.7;4.01;9.12
|
||||
uk:GB80_Charioteer;1.6;1.16;1.4;1.27;1.34
|
||||
uk:GB81_FV4004;1.2;1.05;1.4;1.11;1.2
|
||||
uk:GB85_Cromwell_Berlin;1.9;1.7;1.5;1.55;1.94
|
||||
uk:GB87_Chieftain_T95_turret;1.4;1.17;1.4;1.25;1.35
|
||||
uk:GB93_Caernarvon_AX;1.3;1.13;1.4;1.25;1.35
|
||||
uk:GB94_Centurion_Mk5-1_RAAC;1.3;1.12;1.5;1.28;1.35
|
||||
uk:GB97_Chimera;1.3;1.15;1.5;1.32;1.35
|
||||
uk:GB99_Turtle_Mk1;1.4;1.18;1.4;1.22;1.35
|
||||
uk:GB_Centurion_MkDF;1.3;1.12;1.5;1.29;1.35
|
||||
uk:GB_Churchill_MkVI;2.1;1.73;1.4;1.54;1.77
|
||||
uk:GB_Churchill_MkVIII;2.1;1.64;1.4;1.56;1.79
|
||||
uk:GB_FV301;1.4;1.07;1.5;1.25;1.35
|
||||
uk:GB_Sherman_V;2.6;2.28;1.7;1.96;2.11
|
||||
uk:GB_Vickers_Cruiser;1.1;1;1.5;1.11;1.2
|
||||
uk:Sentinel_AC1;3;2.88;1.9;2.55;3.47
|
||||
usa:A05_M4_105BD;2.7;2.4;1.7;1.96;2.12
|
||||
usa:A100_T49;1.4;1.53;1.5;1.29;1.34
|
||||
usa:A102_T28_concept;1.7;1.47;1.4;1.27;1.62
|
||||
usa:A104_M4A3E8A;1.9;1.88;1.5;1.54;1.84
|
||||
usa:A111_T25_Pilot;1.3;1.27;1.5;1.26;1.35
|
||||
usa:A115_Chrysler_K;1.4;1.16;1.4;1.3;1.35
|
||||
usa:A117_T26E5;1.4;1.15;1.4;1.27;1.35
|
||||
usa:A121_T26E3;1.5;1.54;1.4;1.31;1.61
|
||||
usa:A122_TS-5;1.4;1.15;1.4;1.23;1.35
|
||||
usa:A124_T54E2;1.4;1.15;1.4;1.29;1.35
|
||||
usa:A125_AEP_1;1.1;1.02;1.4;1.15;1.14
|
||||
usa:A130_Super_Hellcat;1.7;1.51;1.4;1.24;1.6
|
||||
usa:A132_T77;1.3;1.15;1.4;1.29;1.35
|
||||
usa:A136_T42;1.5;1.54;1.4;1.29;1.61
|
||||
usa:A140_ASTRON_REX_105;1.3;1.31;1.5;1.31;1.35
|
||||
usa:A141_M-4-Y;1.4;1.16;1.4;1.27;1.35
|
||||
usa:A142_Pawlack_Tank;2.1;1.68;1.4;1.58;1.85
|
||||
usa:A146_TL_7_120;1.1;1.02;1.4;1.14;1.14
|
||||
usa:A150_MBT_B;1.2;1.02;1.4;1.21;1.13
|
||||
usa:A151_TS_60;1.3;1.14;1.4;1.06;1.15
|
||||
usa:A175_ATAC;1.1;1.02;1.5;1.11;1.32
|
||||
usa:A68_T28D;1.4;1.2;1.4;1.28;1.35
|
||||
usa:A77_T6M;3;2.72;1.9;2.52;3.24
|
||||
usa:A94_T37;1.9;1.73;1.6;1.55;2.21
|
||||
usa:A99_T92E1;1.1;1.1;1.5;1.2;1.2
|
||||
usa:M-3-Y;1.4;1.14;1.4;1.28;1.35
|
||||
usa:M-3-Y-Midas;1.4;1.14;1.4;1.28;1.35
|
||||
usa:M-5-Y;1.1;1.02;1.4;1.2;1.14
|
||||
usa:M-7-Y;1.7;1.32;1.4;1.32;1.61
|
||||
usa:M103;1.1;1.02;1.4;1.14;1.13
|
||||
usa:M10_Wolverine;3.2;2.18;1.5;1.96;2.13
|
||||
usa:M18E2BP;1.9;1.65;1.5;1.57;2.02
|
||||
usa:M18_Hellcat;2.1;1.58;1.4;1.51;2.99
|
||||
usa:M22_Locust;3.8;4.23;2.1;3;5.59
|
||||
usa:M24_Chaffee;1.9;1.73;1.6;1.55;2.36
|
||||
usa:M24_Chaffee_BP;1.9;1.73;1.6;1.55;2.36
|
||||
usa:M2_lt;5.5;5.28;3.3;6.76;7.39
|
||||
usa:M2_med;3.6;4.29;2.2;2.93;5.54
|
||||
usa:M36_BP;2.1;1.58;1.4;1.53;1.85
|
||||
usa:M36_Slagger;2.1;1.58;1.4;1.54;1.85
|
||||
usa:M3_Grant;3;2.38;1.9;2.55;3.13
|
||||
usa:M3_Stuart;4.4;4.29;2.7;4.23;5.89
|
||||
usa:M41_Bulldog;1.6;1.49;1.5;1.25;1.61
|
||||
usa:M46_CL;1.1;1.04;1.4;1.08;1.17
|
||||
usa:M46_Patton;1.1;1.08;1.4;1.09;1.17
|
||||
usa:M4A2E4;2.6;2.28;1.7;1.96;2.13
|
||||
usa:M4A3E8_BP;1.9;1.88;1.5;1.55;1.84
|
||||
usa:M4A3E8_Sherman;1.9;1.88;1.5;1.55;1.84
|
||||
usa:M4_Sherman;2.7;1.98;1.7;1.95;2.12
|
||||
usa:M5_Stuart;3.7;3.48;2.1;2.94;5.57
|
||||
usa:M6;2.1;1.6;1.4;1.58;1.8
|
||||
usa:M6A2E1;1.6;1.32;1.4;1.33;1.62
|
||||
usa:M6A2E1_exp;1.4;1.07;1.4;1.33;1.35
|
||||
usa:M6E2BP;2.1;1.6;1.4;1.57;1.77
|
||||
usa:M6E2V2_BP;2.1;1.64;1.4;1.53;1.78
|
||||
usa:M7_med;3.1;2.38;1.9;2.54;2.98
|
||||
usa:M8A1;4;2.73;1.8;2.54;2.87
|
||||
usa:Pershing;1.3;1.33;1.5;1.25;1.35
|
||||
usa:Ram-II;2.5;2.22;1.7;1.97;2.12
|
||||
usa:Sherman_Jumbo;1.9;1.88;1.5;1.56;1.8
|
||||
usa:T14;3.2;2.35;1.5;1.97;2.13
|
||||
usa:T18;5.5;4.48;2.2;4.43;5.65
|
||||
usa:T1_E6;4.4;5;2.7;4.12;8.54
|
||||
usa:T1_hvy;3.3;2;1.5;1.96;2.13
|
||||
usa:T20;1.5;1.54;1.4;1.28;1.61
|
||||
usa:T21;1.9;1.81;1.6;1.57;2.27
|
||||
usa:T21_BP;1.9;1.81;1.6;1.56;2.24
|
||||
usa:T23E3;1.5;1.54;1.4;1.25;1.61
|
||||
usa:T25_2;1.7;1.4;1.4;1.23;1.61
|
||||
usa:T25_AT;1.7;1.44;1.4;1.26;1.61
|
||||
usa:T26_E4_SuperPershing;1.3;1.2;1.5;1.29;1.35
|
||||
usa:T28;1.4;1.16;1.4;1.23;1.35
|
||||
usa:T28_Prototype;1.4;1.16;1.4;1.24;1.35
|
||||
usa:T29;1.7;1.32;1.4;1.31;1.61
|
||||
usa:T2_lt;4.3;5.45;2.7;3.9;8.26
|
||||
usa:T2_med;4.6;5;2.5;4.23;7.11
|
||||
usa:T30;1.1;1.05;1.4;1.12;1.17
|
||||
usa:T32;1.4;1.16;1.4;1.29;1.35
|
||||
usa:T34_hvy;1.3;1.07;1.4;1.3;1.35
|
||||
usa:T34_hvy_Freedom;1.4;1.07;1.4;1.31;1.35
|
||||
usa:T40;4;2.38;1.8;2.54;3.13
|
||||
usa:T49;3.2;2.18;1.5;1.97;2.08
|
||||
usa:T49_Fearless;1.4;1.53;1.5;1.28;1.34
|
||||
usa:T54E1;1.1;1.06;1.4;1.1;1.16
|
||||
usa:T69;1.3;1.33;1.5;1.27;1.35
|
||||
usa:T71;1.6;1.49;1.5;1.27;1.6
|
||||
usa:T7_Combat_Car;4.4;5.58;2.7;4.26;8.54
|
||||
usa:T82;4.1;13.5;1.9;2.78;5.78
|
||||
usa:T95;1.2;1.05;1.4;1.11;1.12
|
||||
usa:T95E2;1.3;1.33;1.5;1.25;1.35
|
||||
ussr:A-20;3.1;2.72;1.9;2.54;3
|
||||
ussr:A-32;3;2.85;1.9;2.52;3.43
|
||||
ussr:AT-1;5.5;3.99;2.2;3.99;8.51
|
||||
ussr:BT-2;4.3;4.71;2.7;4.18;6.52
|
||||
ussr:BT-7;3.6;2.98;2.1;3.06;5.51
|
||||
ussr:BT-SV;3.8;2.86;2.1;3.16;5.58
|
||||
ussr:Churchill_LL;3.2;2.27;1.5;1.97;2.13
|
||||
ussr:GAZ-74b;4;2.48;1.8;2.53;3.05
|
||||
ussr:IS;1.6;1.44;1.4;1.32;1.62
|
||||
ussr:IS-2Sh;1.4;1.15;1.4;1.31;1.35
|
||||
ussr:IS-3;1.4;1.16;1.4;1.3;1.35
|
||||
ussr:IS8;1.2;1.02;1.4;1.12;1.15
|
||||
ussr:ISU-152;1.6;1.13;1.4;1.38;1.35
|
||||
ussr:K-91;1.1;1.02;1.4;1.1;1.12
|
||||
ussr:KV-13;1.5;1.67;1.4;1.26;1.61
|
||||
ussr:KV-1s;2.3;1.6;1.4;1.6;1.82
|
||||
ussr:KV-1s-BP;2.3;1.5;1.4;1.64;1.83
|
||||
ussr:KV-220;3.2;2.27;1.5;1.96;2.13
|
||||
ussr:KV-3;1.7;1.44;1.4;1.33;1.62
|
||||
ussr:KV-5;1.5;1.15;1.4;1.29;1.35
|
||||
ussr:KV1;3.2;2.11;1.5;1.95;2.13
|
||||
ussr:KV2;2.4;2.25;1.4;1.52;1.85
|
||||
ussr:KV4;1.4;1.13;1.4;1.3;1.35
|
||||
ussr:LTP;3.8;2.88;2.1;3.16;5.56
|
||||
ussr:M3_Stuart_LL;3.7;5.04;2.1;2.86;5.51
|
||||
ussr:MS-1obr21;4.3;4.71;2.7;4.18;6.98
|
||||
ussr:MT25;2;1.79;1.6;1.56;2.06
|
||||
ussr:Matilda_II_LL;2.5;2.22;1.7;1.96;2.12
|
||||
ussr:Object252;1.4;1.14;1.4;1.33;1.35
|
||||
ussr:Object252_Fearless;1.4;1.41;1.4;1.33;1.35
|
||||
ussr:Object_704;1.1;1.05;1.4;1.1;1.13
|
||||
ussr:R105_BT_7A;3.8;6.27;2.1;3.86;5.64
|
||||
ussr:R107_LTB;1.6;1.56;1.5;1.28;1.61
|
||||
ussr:R109_T54S;1.4;1.34;1.5;1.29;1.34
|
||||
ussr:R111_ISU130;1.5;1.16;1.4;1.23;1.35
|
||||
ussr:R112_T54_45;1.3;1.37;1.5;1.31;1.35
|
||||
ussr:R113_Object_730;1.4;1.15;1.4;1.31;1.35
|
||||
ussr:R115_IS-3_auto;1.4;1.15;1.4;1.3;1.35
|
||||
ussr:R116_ISU122C_Berlin;1.8;1.45;1.4;1.22;1.62
|
||||
ussr:R127_T44_100_P;1.3;1.33;1.5;1.27;1.35
|
||||
ussr:R131_LTG;1.6;1.61;1.5;1.28;1.61
|
||||
ussr:R134_Object_252U;1.4;1.14;1.4;1.33;1.35
|
||||
ussr:R140_M4A2_Loza;1.9;1.88;1.5;1.55;1.84
|
||||
ussr:R146_STG;1.3;1.33;1.5;1.33;1.35
|
||||
ussr:R154_T-34E-43;2.6;2.22;1.7;1.96;2.11
|
||||
ussr:R158_LT_432;1.4;1.34;1.5;1.28;1.34
|
||||
ussr:R159_SU_130PM;1.6;1.16;1.4;1.26;1.34
|
||||
ussr:R160_object_244;2.1;1.71;1.4;1.55;1.82
|
||||
ussr:R172_Object_752;1.1;1.02;1.4;1.13;1.13
|
||||
ussr:R175_IS_2E;1.6;1.47;1.4;1.31;1.61
|
||||
ussr:R180_Object_274A;1.3;1.31;1.5;1.3;1.35
|
||||
ussr:R181_Object_452K;1.2;1.02;1.4;1.15;1.13
|
||||
ussr:R187_Object_590;1.3;1.32;1.5;1.29;1.35
|
||||
ussr:R192_K_2;1.4;1.12;1.4;1.33;1.35
|
||||
ussr:R194_ST_62_var_2;1.3;1.31;1.5;1.28;1.35
|
||||
ussr:R217_Object_Kust;1.5;1.16;1.4;1.27;1.35
|
||||
ussr:R43_T-70_57;3.8;3.41;2.1;3.43;5.49
|
||||
ussr:R63_ST_IBD;1.2;1.02;1.4;1.17;1.14
|
||||
ussr:R71_IS_2B;1.6;1.44;1.4;1.33;1.61
|
||||
ussr:R98_T44_85;1.5;1.64;1.4;1.26;1.61
|
||||
ussr:R_Object_84;1.1;1.07;1.5;1.12;1.17
|
||||
ussr:ST_I;1.2;1.02;1.4;1.16;1.13
|
||||
ussr:SU-100;2.1;1.57;1.4;1.55;1.81
|
||||
ussr:SU-101;1.5;1.15;1.4;1.26;1.35
|
||||
ussr:SU-152;1.8;2;1.4;1.38;1.61
|
||||
ussr:SU-76;4.2;3.6;1.9;3.18;5.56
|
||||
ussr:SU-85;3.2;1.99;1.5;1.97;2.12
|
||||
ussr:SU100M1;1.7;1.35;1.4;1.25;1.61
|
||||
ussr:SU100Y;2.1;1.53;1.4;1.57;1.89
|
||||
ussr:SU122_44;1.8;1.45;1.4;1.25;1.61
|
||||
ussr:SU122_54;1.2;1.05;1.4;1.03;1.14
|
||||
ussr:SU76I;4.1;3.31;1.9;3.18;5.47
|
||||
ussr:SU_85I;3.1;2.3;1.5;1.98;2.12
|
||||
ussr:T-127;3.8;2.76;2.1;3.16;5.52
|
||||
ussr:T-26;5.5;5.07;3.3;6.16;8.2
|
||||
ussr:T-28;3;2.85;1.9;2.54;3.09
|
||||
ussr:T-34;2.7;2.01;1.7;1.96;2.12
|
||||
ussr:T-34-85;1.9;1.71;1.5;1.58;1.87
|
||||
ussr:T-34-85_Rudy;1.5;1.67;1.4;1.26;1.61
|
||||
ussr:T-34-85_Victory;1.9;1.88;1.5;1.57;1.87
|
||||
ussr:T-43;1.5;1.6;1.4;1.25;1.61
|
||||
ussr:T-44;1.3;1.33;1.5;1.34;1.35
|
||||
ussr:T-46;3.8;4.32;2.1;2.83;5.6
|
||||
ussr:T-54;1.1;1.1;1.4;1.09;1.16
|
||||
ussr:T150;2.1;1.55;1.4;1.59;1.82
|
||||
ussr:T34_85BP;1.9;1.88;1.5;1.57;1.87
|
||||
ussr:T34_85TUR;1.5;1.58;1.4;1.29;1.62
|
||||
ussr:Tetrarch_LL;4.3;3.88;2.7;3.88;8.51
|
||||
ussr:Valentine_LL;2.9;4.55;1.9;2.55;3.42
|
||||
|
@@ -1,3 +1,4 @@
|
||||
import { useModel } from "../hooks/useModel";
|
||||
import { Guess, GuessState } from "../stores/guess";
|
||||
import { SmartCanvas } from "./SmartCanvas";
|
||||
import { Controls } from "./Tankopedia/HeroSection/components/TankSandbox/components/Control";
|
||||
@@ -12,6 +13,9 @@ export function GuessRenderer() {
|
||||
const helpingReveal = Guess.use((state) => state.helpingReveal);
|
||||
const isRevealed = helpingReveal || guessState !== GuessState.NotGuessed;
|
||||
|
||||
const id = Guess.use((state) => state.tank.id);
|
||||
const { hasPbr } = useModel(id);
|
||||
|
||||
return (
|
||||
<SmartCanvas
|
||||
style={{
|
||||
@@ -24,7 +28,7 @@ export function GuessRenderer() {
|
||||
camera={{ position: [-5, 5, -5] }}
|
||||
>
|
||||
<Controls zoomable={false} />
|
||||
<Lighting />
|
||||
<Lighting hasPbr={hasPbr} />
|
||||
<TankModel />
|
||||
</SmartCanvas>
|
||||
);
|
||||
|
||||
@@ -43,7 +43,7 @@ export const MixerScene = forwardRef<HTMLCanvasElement>((_, ref) => {
|
||||
target={[0, 0.5, 0]}
|
||||
/>
|
||||
|
||||
<Lighting />
|
||||
<Lighting hasPbr={false} />
|
||||
<SceneProps />
|
||||
|
||||
<Suspense fallback={<MixerFallback />}>
|
||||
|
||||
+65
-19
@@ -1,4 +1,6 @@
|
||||
import { useFrame } from "@react-three/fiber";
|
||||
import { blueDark, orangeDark } from "@radix-ui/colors";
|
||||
import { ContactShadows } from "@react-three/drei";
|
||||
import { invalidate, useFrame } from "@react-three/fiber";
|
||||
import { clamp, times } from "lodash-es";
|
||||
import { Quicklime } from "quicklime";
|
||||
import {
|
||||
@@ -12,25 +14,35 @@ import { HemisphereLight, SpotLight, type Group } from "three";
|
||||
import { degToRad, lerp } from "three/src/math/MathUtils.js";
|
||||
import { Tankopedia } from "../../../../../../stores/tankopedia";
|
||||
import { TankopediaPersistent } from "../../../../../../stores/tankopediaPersistent";
|
||||
import { HelpingSpotLight } from "../../../../../HelpingSpotLight";
|
||||
import { TankopediaDisplay } from "../../../../../../stores/tankopediaPersistent/constants";
|
||||
|
||||
const ANGLE = degToRad(12);
|
||||
const ANGLE = degToRad(15);
|
||||
const REVEAL_ANIMATION_TIME = 3;
|
||||
const TRANSITION_ANIMATION_TIME = 0.5;
|
||||
|
||||
const LIGHTS_COUNT = 4;
|
||||
const LIGHTS_COUNT = 3;
|
||||
const THETA_OFFSET = degToRad(180 - 45);
|
||||
|
||||
const LIGHT_DISTANCE = 20;
|
||||
const LIGHT_HEIGHT_0 = 4;
|
||||
const LIGHT_HEIGHT_1 = 6;
|
||||
const INTENSITY_0 = 6 * 9;
|
||||
const INTENSITY_1 = 3 * 9;
|
||||
const HEMISPHERE_INTENSITY = 2;
|
||||
const LIGHT_HEIGHT_0 = 7;
|
||||
const LIGHT_HEIGHT_1 = 10;
|
||||
|
||||
const INTENSITY_0 = 2 ** 6;
|
||||
const INTENSITY_1 = 2 ** 3;
|
||||
const HEMISPHERE_INTENSITY = 2 ** 0.7;
|
||||
const NON_PBR_FACTOR = 2;
|
||||
|
||||
const SHADOW_RESOLUTION = 2 ** 9;
|
||||
const SHADOW_FOCUS = 2 ** 0;
|
||||
|
||||
export const transitionEvent = new Quicklime<number>(0);
|
||||
|
||||
export function Lighting() {
|
||||
const wrapper = useRef<Group>(null!);
|
||||
interface Props {
|
||||
hasPbr: boolean;
|
||||
}
|
||||
|
||||
export function Lighting({ hasPbr }: Props) {
|
||||
const wrapper = useRef<Group>(null);
|
||||
|
||||
const highGraphics = TankopediaPersistent.use((state) => state.highGraphics);
|
||||
const requestedDisplay = Tankopedia.use((state) => state.requestedDisplay);
|
||||
@@ -61,8 +73,20 @@ export function Lighting() {
|
||||
|
||||
return (
|
||||
<>
|
||||
<ContactShadows
|
||||
near={0}
|
||||
far={2 ** 6}
|
||||
width={1.5}
|
||||
height={1.5}
|
||||
blur={2 ** 0.5}
|
||||
opacity={2 ** -0.4}
|
||||
resolution={2 ** 7}
|
||||
depthWrite={false}
|
||||
/>
|
||||
|
||||
{animate && (
|
||||
<Animator
|
||||
hasPbr={hasPbr}
|
||||
t0={t0}
|
||||
animationTime={animationTime}
|
||||
wrapper={wrapper}
|
||||
@@ -73,21 +97,29 @@ export function Lighting() {
|
||||
)}
|
||||
|
||||
<group ref={wrapper}>
|
||||
<hemisphereLight intensity={0} color="#ffffff" groundColor="#afafaf" />
|
||||
<hemisphereLight
|
||||
intensity={0}
|
||||
color={blueDark.blue12}
|
||||
groundColor={orangeDark.orange8}
|
||||
/>
|
||||
|
||||
{times(LIGHTS_COUNT, (index) => {
|
||||
const x = index / (LIGHTS_COUNT - 1);
|
||||
const theta = 2 * Math.PI * (index / LIGHTS_COUNT) + THETA_OFFSET;
|
||||
const position = [
|
||||
LIGHT_DISTANCE * Math.sin(theta),
|
||||
-LIGHT_DISTANCE * Math.sin(theta),
|
||||
lerp(LIGHT_HEIGHT_0, LIGHT_HEIGHT_1, x),
|
||||
LIGHT_DISTANCE * Math.cos(theta),
|
||||
] as const;
|
||||
const intensity = lerp(INTENSITY_0, INTENSITY_1, x);
|
||||
|
||||
const light = useRef<SpotLight>(null!);
|
||||
|
||||
// useHelper(light, SpotLightHelper);
|
||||
|
||||
return (
|
||||
<HelpingSpotLight
|
||||
userData={{ index }}
|
||||
<spotLight
|
||||
ref={light}
|
||||
key={index}
|
||||
position={position}
|
||||
intensity={intensity}
|
||||
@@ -96,6 +128,9 @@ export function Lighting() {
|
||||
decay={1}
|
||||
color="#ffffff"
|
||||
angle={0}
|
||||
target-position={[0, 1.5, 0]}
|
||||
shadow-mapSize={[SHADOW_RESOLUTION, SHADOW_RESOLUTION]}
|
||||
shadow-focus={SHADOW_FOCUS}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
@@ -109,18 +144,29 @@ interface AnimatorProps {
|
||||
|
||||
t0: RefObject<number>;
|
||||
animationTime: RefObject<number>;
|
||||
wrapper: RefObject<Group>;
|
||||
wrapper: RefObject<Group | null>;
|
||||
hasPbr: boolean;
|
||||
}
|
||||
|
||||
function Animator({ stop, t0, animationTime, wrapper }: AnimatorProps) {
|
||||
function Animator({ stop, t0, animationTime, wrapper, hasPbr }: AnimatorProps) {
|
||||
const requestedDisplay = Tankopedia.use((state) => state.requestedDisplay);
|
||||
const display = Tankopedia.use((state) => state.display);
|
||||
|
||||
const factor =
|
||||
!hasPbr && display !== TankopediaDisplay.StaticArmor ? NON_PBR_FACTOR : 1;
|
||||
|
||||
useEffect(() => {
|
||||
invalidate();
|
||||
}, [requestedDisplay === display]);
|
||||
|
||||
const apply = useCallback((t: number) => {
|
||||
if (!wrapper.current) return;
|
||||
|
||||
for (const child of wrapper.current.children) {
|
||||
if (child instanceof SpotLight) {
|
||||
child.angle = ANGLE * t;
|
||||
child.angle = ANGLE * t * factor;
|
||||
} else if (child instanceof HemisphereLight) {
|
||||
child.intensity = HEMISPHERE_INTENSITY * t;
|
||||
child.intensity = HEMISPHERE_INTENSITY * t * factor;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+50
-7
@@ -1,7 +1,8 @@
|
||||
import { mauveDark } from "@radix-ui/colors";
|
||||
import { invalidate } from "@react-three/fiber";
|
||||
import { Quicklime, type QuicklimeEvent } from "quicklime";
|
||||
import { useEffect, useRef } from "react";
|
||||
import { Mesh, MeshStandardMaterial } from "three";
|
||||
import { useCallback, useEffect, useRef } from "react";
|
||||
import { Mesh, type WebGLProgramParametersWithUniforms } from "three";
|
||||
|
||||
const SIZE = 2 ** 4;
|
||||
|
||||
@@ -9,7 +10,6 @@ export const screenshotReadyEvent = new Quicklime(false);
|
||||
|
||||
export function SceneProps() {
|
||||
const mesh = useRef<Mesh>(null!);
|
||||
const material = useRef<MeshStandardMaterial>(null);
|
||||
|
||||
useEffect(() => {
|
||||
function handleScreenshotReady(event: QuicklimeEvent<boolean>) {
|
||||
@@ -24,19 +24,62 @@ export function SceneProps() {
|
||||
};
|
||||
}, []);
|
||||
|
||||
const handleBeforeCompile = useCallback(
|
||||
(shader: WebGLProgramParametersWithUniforms) => {
|
||||
shader.uniforms.size = { value: SIZE / 2 };
|
||||
|
||||
shader.vertexShader = `
|
||||
varying vec3 vWorldPosition;
|
||||
|
||||
${shader.vertexShader}
|
||||
`.replace(
|
||||
"#include <worldpos_vertex>",
|
||||
|
||||
`
|
||||
#include <worldpos_vertex>
|
||||
vWorldPosition = (modelMatrix * vec4(transformed, 1.0)).xyz;
|
||||
`,
|
||||
);
|
||||
|
||||
shader.fragmentShader = `
|
||||
varying vec3 vWorldPosition;
|
||||
uniform float size;
|
||||
|
||||
${shader.fragmentShader}
|
||||
`.replace(
|
||||
"#include <color_fragment>",
|
||||
|
||||
`
|
||||
#include <color_fragment>
|
||||
|
||||
vec3 scaled = vWorldPosition / size;
|
||||
float radius = length(scaled.xz);
|
||||
|
||||
if (radius >= 1.0) {
|
||||
discard;
|
||||
}
|
||||
|
||||
diffuseColor.a *= (1.0 - radius);
|
||||
`,
|
||||
);
|
||||
},
|
||||
[],
|
||||
);
|
||||
|
||||
return (
|
||||
<mesh
|
||||
position={[0, -(2 ** -8), 0]}
|
||||
rotation={[-Math.PI / 2, 0, 0]}
|
||||
receiveShadow
|
||||
visible={!screenshotReadyEvent.last!}
|
||||
ref={mesh}
|
||||
receiveShadow
|
||||
>
|
||||
<planeGeometry args={[SIZE, SIZE]} />
|
||||
<meshStandardMaterial
|
||||
ref={material}
|
||||
color="black"
|
||||
color={mauveDark.mauve6}
|
||||
roughness={1}
|
||||
metalness={0}
|
||||
transparent
|
||||
onBeforeCompile={handleBeforeCompile}
|
||||
/>
|
||||
</mesh>
|
||||
);
|
||||
|
||||
+5
-3
@@ -5,11 +5,11 @@ import {
|
||||
useImperativeHandle,
|
||||
useRef,
|
||||
} from "react";
|
||||
import { Fog } from "three";
|
||||
import { applyPitchYawLimits } from "../../../../../core/blitz/applyPitchYawLimits";
|
||||
import { modelTransformEvent } from "../../../../../core/blitzkit/modelTransform";
|
||||
import { Pose, poseEvent } from "../../../../../core/blitzkit/pose";
|
||||
import { useEquipment } from "../../../../../hooks/useEquipment";
|
||||
import { useModel } from "../../../../../hooks/useModel";
|
||||
import { useTankModelDefinition } from "../../../../../hooks/useTankModelDefinition";
|
||||
import { Duel } from "../../../../../stores/duel";
|
||||
import { Tankopedia } from "../../../../../stores/tankopedia";
|
||||
@@ -50,6 +50,9 @@ export const TankSandbox = forwardRef<HTMLCanvasElement, TankSandboxProps>(
|
||||
(state) => state.hideTankModelUnderArmor,
|
||||
);
|
||||
|
||||
const id = Duel.use((state) => state.protagonist.tank.id);
|
||||
const { hasPbr } = useModel(id);
|
||||
|
||||
useImperativeHandle(ref, () => canvas.current!, []);
|
||||
|
||||
function handlePointerDown() {
|
||||
@@ -150,7 +153,6 @@ export const TankSandbox = forwardRef<HTMLCanvasElement, TankSandboxProps>(
|
||||
<SmartCanvas
|
||||
resize={{ debounce: 0 }}
|
||||
ref={canvas}
|
||||
scene={{ fog: new Fog("black", 30, 50) }}
|
||||
gl={{
|
||||
clippingPlanes: [],
|
||||
localClippingEnabled: true,
|
||||
@@ -171,7 +173,7 @@ export const TankSandbox = forwardRef<HTMLCanvasElement, TankSandboxProps>(
|
||||
outline: undefined,
|
||||
}}
|
||||
>
|
||||
<Lighting />
|
||||
<Lighting hasPbr={hasPbr} />
|
||||
|
||||
<SceneProps />
|
||||
{(display === TankopediaDisplay.Model ||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { assertSecret } from "@blitzkit/core";
|
||||
import { LocalVFS } from "@blitzkit/core/src/blitzkit/vfs/local";
|
||||
|
||||
export const vfs = new LocalVFS(assertSecret(import.meta.env.GAME_DIR));
|
||||
export const vfs = new LocalVFS(assertSecret(import.meta.env.CLIENT_DIR));
|
||||
@@ -11,6 +11,13 @@ export const getStaticPaths = mixStaticPaths(_getStaticPaths, async () => {
|
||||
.dir(`Data/Gfx/Shared/tank-supply/ammunition/big`)
|
||||
.then((files) => files.filter((file) => file.endsWith("_l.txt")));
|
||||
|
||||
console.log(
|
||||
"Shell files raw",
|
||||
await vfs.dir(`Data/Gfx/Shared/tank-supply/ammunition/big`),
|
||||
);
|
||||
|
||||
console.log("Shell file paths", files);
|
||||
|
||||
for (const file of files) {
|
||||
const id = file.match(/(.+)_l\.txt/)![1];
|
||||
const sizes = (
|
||||
|
||||
@@ -107,9 +107,6 @@ async function extractModel(vfs: AbstractVFS, path: string) {
|
||||
if (textures) {
|
||||
const baseColor = await readBaseColor(
|
||||
`Data/3d/${dirname(path)}/${textures.baseColorMap ?? textures.albedo}`,
|
||||
textures.miscMap
|
||||
? `Data/3d/${dirname(path)}/${textures.miscMap}`
|
||||
: undefined,
|
||||
);
|
||||
material.setBaseColorTexture(
|
||||
document
|
||||
@@ -180,6 +177,19 @@ async function extractModel(vfs: AbstractVFS, path: string) {
|
||||
}
|
||||
}
|
||||
|
||||
if (textures.miscMap) {
|
||||
material.setOcclusionTexture(
|
||||
document
|
||||
.createTexture(node.materialName)
|
||||
.setMimeType("image/webp")
|
||||
.setImage(
|
||||
await readOcclusion(
|
||||
`Data/3d/${dirname(path)}/${textures.miscMap}`,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
if (textures.baseRMMap) {
|
||||
material.setMetallicRoughnessTexture(
|
||||
document
|
||||
@@ -368,46 +378,18 @@ async function extractModel(vfs: AbstractVFS, path: string) {
|
||||
return document;
|
||||
}
|
||||
|
||||
async function readBaseColor(path: string, occlusionPath?: string) {
|
||||
const baseRaw = await readTexture(path);
|
||||
const occlusionRaw = occlusionPath
|
||||
? await readTexture(occlusionPath)
|
||||
: undefined;
|
||||
const base = await sharp(baseRaw.data, { raw: baseRaw }).raw().toBuffer();
|
||||
const occlusion = occlusionRaw
|
||||
? await sharp(occlusionRaw.data, { raw: occlusionRaw })
|
||||
.extractChannel(3)
|
||||
.raw()
|
||||
.toBuffer()
|
||||
: undefined;
|
||||
async function readBaseColor(path: string) {
|
||||
const raw = await readTexture(path);
|
||||
const image = await sharp(raw.data, { raw }).webp().toBuffer();
|
||||
|
||||
const combined = Buffer.alloc(baseRaw.width * baseRaw.height * 4);
|
||||
return image;
|
||||
}
|
||||
|
||||
for (let i = 0; i < baseRaw.width * baseRaw.height; i++) {
|
||||
let c = 1;
|
||||
async function readOcclusion(path: string) {
|
||||
const raw = await readTexture(path);
|
||||
|
||||
if (occlusionRaw) {
|
||||
const x = i % baseRaw.width;
|
||||
const y = Math.floor(i / baseRaw.width);
|
||||
const u = Math.floor(x * (occlusionRaw.width / baseRaw.width));
|
||||
const v = Math.floor(y * (occlusionRaw.height / baseRaw.height));
|
||||
|
||||
const occlusionI = u + v * occlusionRaw.width;
|
||||
|
||||
c = occlusion![occlusionI] / 255;
|
||||
}
|
||||
|
||||
const alpha = base[i * 4 + 3];
|
||||
|
||||
combined[i * 4 + 0] = Math.round(base[i * 4 + 0] * c);
|
||||
combined[i * 4 + 1] = Math.round(base[i * 4 + 1] * c);
|
||||
combined[i * 4 + 2] = Math.round(base[i * 4 + 2] * c);
|
||||
combined[i * 4 + 3] = alpha;
|
||||
}
|
||||
|
||||
const image = await sharp(combined, {
|
||||
raw: { width: baseRaw.width, height: baseRaw.height, channels: 4 },
|
||||
})
|
||||
const image = await sharp(raw.data, { raw })
|
||||
.extractChannel(3)
|
||||
.webp()
|
||||
.toBuffer();
|
||||
|
||||
@@ -416,7 +398,7 @@ async function readBaseColor(path: string, occlusionPath?: string) {
|
||||
|
||||
async function readRoughnessMetallic(path: string) {
|
||||
const raw = await readTexture(path);
|
||||
const blitz = sharp(raw.data, { raw: raw });
|
||||
const blitz = sharp(raw.data, { raw });
|
||||
const metallicness = await blitz?.extractChannel(1).raw().toBuffer();
|
||||
const roughness = await blitz?.extractChannel(3).raw().toBuffer();
|
||||
|
||||
|
||||
@@ -5,6 +5,8 @@ import { LinkI18n } from "../../components/LinkI18n";
|
||||
import { PageWrapper } from "../../components/PageWrapper";
|
||||
import BaseLayout from "../../layouts/BaseLayout.astro";
|
||||
|
||||
export { getStaticPaths } from "./_index";
|
||||
|
||||
const { locale } = Astro.props;
|
||||
---
|
||||
|
||||
|
||||
@@ -1,20 +1,22 @@
|
||||
import type { APIContext } from 'astro';
|
||||
|
||||
const ALLOW_ROBOTS = import.meta.env.ALLOW_ROBOTS;
|
||||
import { environmentConfig } from "@blitzkit/core";
|
||||
import type { APIContext } from "astro";
|
||||
|
||||
export async function GET({ request }: APIContext) {
|
||||
const config = environmentConfig();
|
||||
|
||||
const flags: Record<string, string | null> = {
|
||||
'User-agent': '*',
|
||||
Allow: ALLOW_ROBOTS ? '/' : null,
|
||||
Disallow: ALLOW_ROBOTS ? null : '/',
|
||||
"User-agent": "*",
|
||||
Allow: config.robots ? "/" : null,
|
||||
Disallow: config.robots ? null : "/",
|
||||
|
||||
space: null,
|
||||
|
||||
Sitemap: `${new URL(request.url).origin}/sitemap-index.xml`,
|
||||
};
|
||||
|
||||
return new Response(
|
||||
Object.entries(flags)
|
||||
.map(([key, value]) => (value === null ? '' : `${key}: ${value}`))
|
||||
.join('\n'),
|
||||
.map(([key, value]) => (value === null ? "" : `${key}: ${value}`))
|
||||
.join("\n"),
|
||||
);
|
||||
}
|
||||
Reference in new issue
Block a user