Compare commits

...
94 Commits
Author SHA1 Message Date
TrèsAbhi bbe53deb98 feat: logs 2025-08-04 21:06:24 -05:00
TrèsAbhi 1f07c2be74 feat: better logs 2025-08-04 21:00:40 -05:00
TrèsAbhi ea744b673a feat: add progress bar to hero section 2025-08-04 20:30:39 -05:00
TrèsAbhi d8a6cac52f fix: align footer second row 2025-08-04 20:15:16 -05:00
TrèsAbhi 1524b9a35d fix: disallow robots on non-master domains 2025-08-04 20:11:51 -05:00
TrèsAbhi 36738f57a9 fix: add mediump default 2025-08-04 20:09:50 -05:00
TrèsAbhi a704b291fd fix: consider shells 2025-08-01 12:37:40 -05:00
TrèsAbhi e1b5b21fae feat: cursor 2025-08-01 12:25:09 -05:00
TrèsAbhi 097f2792ae feat: cursor 2025-07-31 20:51:54 -05:00
TrèsAbhi 089d0e9682 feat: prettier 2025-07-31 20:40:02 -05:00
TrèsAbhi 6a92b3ae80 feat: x axis 2025-07-31 20:18:36 -05:00
TrèsAbhi 1e91065033 feat: assault graph 2025-07-31 14:42:12 -05:00
TrèsAbhi b20bb97ea3 feat: reorder stuff 2025-07-31 14:12:14 -05:00
TrèsAbhi ba97a9f28b feat: some implementation 2025-07-31 14:07:21 -05:00
TrèsAbhi 81e480f983 fix: remove debug code 2025-07-31 13:44:55 -05:00
TrèsAbhi 40e4e0a274 feat: start of assault shells 2025-07-31 13:44:14 -05:00
TrèsAbhi 83b7de77de feat: start of assault shells 2025-07-31 13:40:30 -05:00
TrèsAbhi 20f7119854 New translations en.json (Russian) (#158) 2025-07-28 12:19:29 -05:00
TrèsAbhi 275ddcc7a6 New Crowdin updates (#157) 2025-07-27 20:54:42 -05:00
TrèsAbhi 4858f31da4 feat: logs 2025-07-27 20:42:22 -05:00
TrèsAbhi 4bc255a624 fix: clear filters no longer shows up after searching and clearing the search bar 2025-07-27 20:36:23 -05:00
TrèsAbhi 17755641a1 feat: sorting by he shell penetratoin 2025-07-27 20:31:21 -05:00
TrèsAbhi 0e6b0087ce fix: tankopedia compare acknoledge selected equipment 2025-07-27 20:27:43 -05:00
TrèsAbhi fcd084a86f fix: tankopedia compare acknoledge selected shell 2025-07-27 20:26:58 -05:00
TrèsAbhi af699ff5b7 fix: guns don't appear transparent when moved far away from camera 2025-07-27 20:15:08 -05:00
TrèsAbhi 93665df223 feat: scrollable hero 2025-07-27 20:11:16 -05:00
TrèsAbhi f8b4f9372a fix: stop equipment definitions fetch spam 2025-07-27 20:09:08 -05:00
TrèsAbhi e84e15daf4 fix: missing navbar background images 2025-07-27 20:07:47 -05:00
TrèsAbhi d7af7e19dd fix: integrated navbar 2025-07-27 15:36:46 -05:00
TrèsAbhi c5cf172e42 fix: remove text outline, it just doesn't work 2025-07-27 15:34:22 -05:00
TrèsAbhi 2e8cac885c Update rating-na.yml 2025-07-15 23:37:10 -05:00
TrèsAbhi 9ed4a856bf Update rating-asia.yml 2025-07-15 23:36:36 -05:00
TrèsAbhi eedd4b3f27 Update rating-eu.yml 2025-07-15 23:36:03 -05:00
TrèsAbhi 3b7fe0b114 Update averages.yml 2025-07-15 11:17:37 -05:00
TrèsAbhi a6d66b94f5 Update host-bot.yml 2025-07-15 09:43:27 -05:00
TrèsAbhi c7a7bbb809 Update host-bot.yml 2025-07-15 09:41:44 -05:00
TrèsAbhi 02ce6ba8d9 Update index.tsx 2025-07-12 12:46:40 -05:00
TrèsAbhi 9dd057d594 Update host-bot.yml 2025-07-11 18:13:13 -05:00
TrèsAbhi 64ec981496 Update host-bot.yml 2025-07-11 18:11:54 -05:00
TrèsAbhi 8afafdeece Update host-bot.yml 2025-07-11 18:10:46 -05:00
TrèsAbhi 6b9fd1d392 fix: time out handling 2025-07-11 12:34:33 -05:00
TrèsAbhi c1efc50134 feat: disable popular tanks 2025-07-11 12:31:10 -05:00
TrèsAbhi b4b1f4e916 feat: cleaner logging 2025-07-11 12:28:50 -05:00
TrèsAbhi 3de0c40ce3 fix: retry host 2025-07-11 12:27:57 -05:00
TrèsAbhi 893bfa8393 feat: tags 2025-06-26 10:36:51 -05:00
TrèsAbhi cc25535c34 Update Party3.astro 2025-06-26 10:26:13 -05:00
TrèsAbhi a4cdf16fcd Update Party3.astro 2025-06-26 10:26:01 -05:00
TrèsAbhi 36588b11e6 Update package.json 2025-06-26 10:21:25 -05:00
TrèsAbhi e927838c14 Update astro.config.mjs 2025-06-26 10:21:18 -05:00
TrèsAbhi 5197ebb6a7 Update Party3.astro 2025-06-26 10:21:07 -05:00
TrèsAbhi 51089a3e91 Update tankModels.ts 2025-06-26 09:55:23 -05:00
TrèsAbhi c6121fd4bd fix: add base 2025-06-25 19:47:21 -05:00
TrèsAbhi 7dca9d3244 Update tankModels.ts 2025-06-09 11:19:27 -05:00
TrèsAbhi abebfcf6c6 feat: branch 2025-06-08 17:32:13 +00:00
TrèsAbhi 470869418c Update website.yml 2025-06-08 12:24:45 -05:00
TrèsAbhi cd2bad3b27 feat: asset base 2025-06-08 17:20:08 +00:00
TrèsAbhi 5e9555aa57 fix: identity encoding 2025-06-07 12:35:23 -05:00
TrèsAbhi 084d55b853 Update commitMultipleFiles.ts 2025-06-07 10:46:45 -05:00
TrèsAbhi a3879f3fa7 Update commitMultipleFiles.ts 2025-06-07 10:08:52 -05:00
TrèsAbhi 135a2d74c4 Update commitMultipleFiles.ts 2025-06-07 09:34:14 -05:00
TrèsAbhi 233f866c9e Update assets.yml 2025-06-06 23:28:21 -05:00
TrèsAbhi 9e880ff24f Update assets.yml 2025-06-06 21:55:03 -05:00
TrèsAbhi 36039563e0 Update assets.yml 2025-06-06 21:54:16 -05:00
TrèsAbhi 022e970537 Update createBlob.ts 2025-06-06 14:48:36 -05:00
TrèsAbhi 51e99ec442 Update applyPatches.ts 2025-06-05 15:52:06 -05:00
TrèsAbhi caeba34ba1 feat: add internals 2025-06-05 14:22:27 -05:00
TrèsAbhi 6d6a634973 fix: a bunch of stupid things 2025-06-05 13:01:50 -05:00
TrèsAbhi 55e6599eaa Update host-bot.yml 2025-06-05 09:23:45 -05:00
TrèsAbhi e146366385 New Crowdin updates (#156)
* New translations en.json (Chinese Simplified)

* New translations en.json (Chinese Simplified)

* New translations en.json (Chinese Simplified)

* New translations en.json (Chinese Simplified)

* New translations en.json (Russian)

* New translations en.json (Chinese Simplified)

* New translations en.json (Chinese Simplified)

* New translations en.json (Chinese Simplified)

* New translations en.json (Chinese Simplified)

* New translations en.json (Chinese Simplified)

* New translations en.json (Chinese Simplified)

* New translations en.json (Chinese Simplified)

* New translations en.json (Chinese Simplified)

* New translations en.json (Chinese Simplified)

* New translations en.json (Chinese Simplified)

* New translations en.json (Chinese Simplified)
2025-06-04 09:16:49 -05:00
TrèsAbhi b1dd319c1e Create discord 2025-05-26 23:31:53 -05:00
TrèsAbhi e7ca8f1b10 feat: remove UAssetAPI 2025-05-23 20:05:08 -05:00
tresabhi 0d8a677ac5 Merge branch 'main' into dev 2025-05-21 13:25:49 -05:00
tresabhi a8dc271e0a feat: update to imported base creators 2025-05-21 13:24:02 -05:00
TrèsAbhi f3d6ba68a7 New Crowdin updates (#154)
* New translations en.json (Ukrainian)

* New translations en.json (French)

* New translations en.json (Spanish)

* New translations en.json (Japanese)

* New translations en.json (Portuguese)

* New translations en.json (Russian)

* New translations en.json (Chinese Simplified)

* New translations en.json (Polish)

* New translations en.json (Ukrainian)

* New translations en.json (French)

* New translations en.json (Spanish)

* New translations en.json (Japanese)

* New translations en.json (Portuguese)

* New translations en.json (Russian)

* New translations en.json (Chinese Simplified)

* New translations en.json (Polish)

* New translations en.json (Russian)

* New translations en.json (Russian)

* New translations en.json (Ukrainian)

* New translations en.json (French)

* New translations en.json (Spanish)

* New translations en.json (Japanese)

* New translations en.json (Portuguese)

* New translations en.json (Russian)

* New translations en.json (Chinese Simplified)

* New translations en.json (Polish)

* New translations en.json (Polish)

* New translations en.json (Russian)

* New translations en.json (Ukrainian)

* New translations en.json (French)

* New translations en.json (Spanish)

* New translations en.json (Japanese)

* New translations en.json (Portuguese)

* New translations en.json (Russian)

* New translations en.json (Chinese Simplified)

* New translations en.json (Polish)

* New translations en.json (Japanese)

* New translations en.json (Japanese)

* New translations en.json (Chinese Simplified)
2025-05-20 09:04:31 -05:00
TrèsAbhi e68b27bac4 fix: don't return on bot 2025-05-19 17:39:02 -05:00
tresabhi d49eef7308 feat: update uasset 2025-05-19 12:47:49 -05:00
tresabhi 6e630a91aa Merge branch 'main' of https://github.com/tresabhi/blitzkit 2025-05-19 12:47:37 -05:00
tresabhi 2c66e79daf Merge branch 'preview' 2025-05-19 12:47:32 -05:00
TrèsAbhi 9a94a4e371 Update rating-na.yml 2025-05-18 19:00:33 -05:00
TrèsAbhi b1372c998d Update rating-eu.yml 2025-05-18 18:59:44 -05:00
TrèsAbhi 4ed93cb38f Update rating-asia.yml 2025-05-18 18:59:15 -05:00
TrèsAbhi 4d1b175c07 Update averages.yml 2025-05-18 18:58:37 -05:00
TrèsAbhi ecfedc32ad Update assets.yml 2025-05-18 18:58:01 -05:00
TrèsAbhi 9da514c329 Update assets.yml 2025-05-18 11:38:41 -05:00
tresabhi ee5386c925 fix: secrets 2025-05-18 09:58:38 -05:00
TrèsAbhi 76f7ae45ce Update index.astro 2025-04-04 21:27:42 -05:00
TresAbhi ad2aaa7bf8 feat: some sketchy code 2025-04-05 02:07:35 +00:00
TresAbhi 2a4375c718 Merge branch 'main' into preview 2025-04-04 20:26:22 +00:00
tresabhi 134566f1d8 feat: hide version... correctly 2025-01-10 12:06:20 -06:00
tresabhi d592a95cae feat: hide on preview 2025-01-10 11:56:00 -06:00
tresabhi 4f74556eb6 feat: hide version 2025-01-10 11:53:14 -06:00
tresabhi 1342f434a3 feat: desc 2025-01-10 11:14:43 -06:00
TrèsAbhi 6110471990 Update index.astro 2025-01-10 11:03:55 -06:00
TrèsAbhi 359eec5209 Update package.json 2025-01-10 10:46:57 -06:00
112 changed files with 3172 additions and 2221 deletions

No files matched your search

+5 -2
View File
@@ -37,8 +37,8 @@ env:
WOTB_GLOSSARY: ${{ secrets.WOTB_GLOSSARY }} WOTB_GLOSSARY: ${{ secrets.WOTB_GLOSSARY }}
WOTB_DLC_CDN: ${{ secrets.WOTB_DLC_CDN }} WOTB_DLC_CDN: ${{ secrets.WOTB_DLC_CDN }}
PUBLIC_WARGAMING_APPLICATION_ID: ${{ secrets.PUBLIC_WARGAMING_APPLICATION_ID }} PUBLIC_WARGAMING_APPLICATION_ID: ${{ secrets.PUBLIC_WARGAMING_APPLICATION_ID }}
PUBLIC_ASSET_REPO: ${{ secrets.PUBLIC_ASSET_REPO }} PUBLIC_ASSET_REPO: blitzkit/assets
PUBLIC_ASSET_BRANCH: ${{ github.event.inputs.cdn_branch || secrets.PUBLIC_ASSET_BRANCH }} PUBLIC_ASSET_BRANCH: main
WOTB_GLOSSARY_DOMAIN: ${{ secrets.WOTB_GLOSSARY_DOMAIN }} WOTB_GLOSSARY_DOMAIN: ${{ secrets.WOTB_GLOSSARY_DOMAIN }}
WOTB_GLOSSARY_PATH: ${{ secrets.WOTB_GLOSSARY_PATH }} WOTB_GLOSSARY_PATH: ${{ secrets.WOTB_GLOSSARY_PATH }}
PUBLIC_PROMOTE_OPENTEST: ${{ secrets.PUBLIC_PROMOTE_OPENTEST }} PUBLIC_PROMOTE_OPENTEST: ${{ secrets.PUBLIC_PROMOTE_OPENTEST }}
@@ -51,6 +51,9 @@ env:
PUBLIC_NITROPAY_ID: ${{ secrets.PUBLIC_NITROPAY_ID }} PUBLIC_NITROPAY_ID: ${{ secrets.PUBLIC_NITROPAY_ID }}
PUBLIC_DEBUG_MISSING_I18N: false PUBLIC_DEBUG_MISSING_I18N: false
PUBLIC_DISCORD_SERVER_ID: ${{ secrets.PUBLIC_DISCORD_SERVER_ID }} PUBLIC_DISCORD_SERVER_ID: ${{ secrets.PUBLIC_DISCORD_SERVER_ID }}
PUBLIC_ASSET_FAST_USER: blitzkit
PUBLIC_ASSET_FAST_REPO: assets
PUBLIC_ASSET_BASE: ${{ secrets.PUBLIC_ASSET_BASE }}
jobs: jobs:
download_client: download_client:
+13
View File
@@ -12,6 +12,19 @@ concurrency:
env: env:
PUBLIC_ASSET_REPO: ${{ secrets.PUBLIC_ASSET_REPO }} PUBLIC_ASSET_REPO: ${{ secrets.PUBLIC_ASSET_REPO }}
PUBLIC_WARGAMING_APPLICATION_ID: ${{ secrets.PUBLIC_WARGAMING_APPLICATION_ID }} PUBLIC_WARGAMING_APPLICATION_ID: ${{ secrets.PUBLIC_WARGAMING_APPLICATION_ID }}
PUBLIC_ASSET_FAST_USER: ${{ secrets.PUBLIC_ASSET_FAST_USER }}
PUBLIC_ASSET_FAST_REPO: ${{ secrets.PUBLIC_ASSET_FAST_REPO }}
PUBLIC_PROMOTE_OPENTEST: ${{ secrets.PUBLIC_PROMOTE_OPENTEST }}
ALLOW_ROBOTS: 'true'
WOTB_GLOSSARY: ${{ secrets.WOTB_GLOSSARY }}
PUBLIC_GOOGLE_TAG_MANAGER_ID: ${{ secrets.PUBLIC_GOOGLE_TAG_MANAGER_ID }}
PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID: ${{ secrets.PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID }}
GOOGLE_APPLICATION_CREDENTIALS: ${{ secrets.GOOGLE_APPLICATION_CREDENTIALS }}
WOTB_GLOSSARY_DOMAIN: ${{ secrets.WOTB_GLOSSARY_DOMAIN }}
WOTB_GLOSSARY_PATH: ${{ secrets.WOTB_GLOSSARY_PATH }}
PUBLIC_DISCORD_SERVER_ID: ${{ secrets.PUBLIC_DISCORD_SERVER_ID }}
PUBLIC_ASSET_BASE: ${{ secrets.PUBLIC_ASSET_BASE }}
PUBLIC_BRANCH: ${{ secrets.PUBLIC_BRANCH }}
jobs: jobs:
build: build:
+5 -3
View File
@@ -20,6 +20,8 @@ env:
PUBLIC_ASSET_REPO: ${{ secrets.PUBLIC_ASSET_REPO }} PUBLIC_ASSET_REPO: ${{ secrets.PUBLIC_ASSET_REPO }}
PUBLIC_ASSET_BRANCH: ${{ secrets.PUBLIC_ASSET_BRANCH }} PUBLIC_ASSET_BRANCH: ${{ secrets.PUBLIC_ASSET_BRANCH }}
PUBLIC_WARGAMING_APPLICATION_ID: ${{ secrets.PUBLIC_WARGAMING_APPLICATION_ID }} PUBLIC_WARGAMING_APPLICATION_ID: ${{ secrets.PUBLIC_WARGAMING_APPLICATION_ID }}
PUBLIC_ASSET_FAST_USER: ${{ secrets.PUBLIC_ASSET_FAST_USER }}
PUBLIC_ASSET_FAST_REPO: ${{ secrets.PUBLIC_ASSET_FAST_REPO }}
jobs: jobs:
host: host:
@@ -27,12 +29,12 @@ jobs:
steps: steps:
- uses: oven-sh/setup-bun@v1 - uses: oven-sh/setup-bun@v1
# with: # with:
# bun-version: 1.1.33 # bun-version: 1.1.33
- name: Download release assets - name: Download release assets
run: | run: |
DOWNLOAD_URL=$(curl -s https://api.github.com/repos/tresabhi/blitzkit/releases/latest \ DOWNLOAD_URL=$(curl -s https://api.github.com/repos/blitzkit/blitzkit/releases/latest \
| grep "browser_download_url.*bot.zip" \ | grep "browser_download_url.*bot.zip" \
| cut -d : -f 2,3 \ | cut -d : -f 2,3 \
| tr -d \") | tr -d \")
+13
View File
@@ -25,4 +25,17 @@ jobs:
DISCORD_TOKEN: ${{ secrets.DISCORD_TOKEN }} DISCORD_TOKEN: ${{ secrets.DISCORD_TOKEN }}
DATABASE_URL: ${{ secrets.DATABASE_URL }} DATABASE_URL: ${{ secrets.DATABASE_URL }}
PUBLIC_WARGAMING_APPLICATION_ID: ${{ secrets.PUBLIC_WARGAMING_APPLICATION_ID }} PUBLIC_WARGAMING_APPLICATION_ID: ${{ secrets.PUBLIC_WARGAMING_APPLICATION_ID }}
PUBLIC_ASSET_FAST_USER: ${{ secrets.PUBLIC_ASSET_FAST_USER }}
PUBLIC_ASSET_FAST_REPO: ${{ secrets.PUBLIC_ASSET_FAST_REPO }}
PUBLIC_PROMOTE_OPENTEST: ${{ secrets.PUBLIC_PROMOTE_OPENTEST }}
ALLOW_ROBOTS: 'true'
WOTB_GLOSSARY: ${{ secrets.WOTB_GLOSSARY }}
PUBLIC_GOOGLE_TAG_MANAGER_ID: ${{ secrets.PUBLIC_GOOGLE_TAG_MANAGER_ID }}
PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID: ${{ secrets.PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID }}
GOOGLE_APPLICATION_CREDENTIALS: ${{ secrets.GOOGLE_APPLICATION_CREDENTIALS }}
WOTB_GLOSSARY_DOMAIN: ${{ secrets.WOTB_GLOSSARY_DOMAIN }}
WOTB_GLOSSARY_PATH: ${{ secrets.WOTB_GLOSSARY_PATH }}
PUBLIC_DISCORD_SERVER_ID: ${{ secrets.PUBLIC_DISCORD_SERVER_ID }}
PUBLIC_ASSET_BASE: ${{ secrets.PUBLIC_ASSET_BASE }}
PUBLIC_BRANCH: ${{ secrets.PUBLIC_BRANCH }}
run: bun build:ratingleaderboard --region=asia run: bun build:ratingleaderboard --region=asia
+13
View File
@@ -25,4 +25,17 @@ jobs:
DISCORD_TOKEN: ${{ secrets.DISCORD_TOKEN }} DISCORD_TOKEN: ${{ secrets.DISCORD_TOKEN }}
DATABASE_URL: ${{ secrets.DATABASE_URL }} DATABASE_URL: ${{ secrets.DATABASE_URL }}
PUBLIC_WARGAMING_APPLICATION_ID: ${{ secrets.PUBLIC_WARGAMING_APPLICATION_ID }} PUBLIC_WARGAMING_APPLICATION_ID: ${{ secrets.PUBLIC_WARGAMING_APPLICATION_ID }}
PUBLIC_ASSET_FAST_USER: ${{ secrets.PUBLIC_ASSET_FAST_USER }}
PUBLIC_ASSET_FAST_REPO: ${{ secrets.PUBLIC_ASSET_FAST_REPO }}
PUBLIC_PROMOTE_OPENTEST: ${{ secrets.PUBLIC_PROMOTE_OPENTEST }}
ALLOW_ROBOTS: 'true'
WOTB_GLOSSARY: ${{ secrets.WOTB_GLOSSARY }}
PUBLIC_GOOGLE_TAG_MANAGER_ID: ${{ secrets.PUBLIC_GOOGLE_TAG_MANAGER_ID }}
PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID: ${{ secrets.PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID }}
GOOGLE_APPLICATION_CREDENTIALS: ${{ secrets.GOOGLE_APPLICATION_CREDENTIALS }}
WOTB_GLOSSARY_DOMAIN: ${{ secrets.WOTB_GLOSSARY_DOMAIN }}
WOTB_GLOSSARY_PATH: ${{ secrets.WOTB_GLOSSARY_PATH }}
PUBLIC_DISCORD_SERVER_ID: ${{ secrets.PUBLIC_DISCORD_SERVER_ID }}
PUBLIC_ASSET_BASE: ${{ secrets.PUBLIC_ASSET_BASE }}
PUBLIC_BRANCH: ${{ secrets.PUBLIC_BRANCH }}
run: bun build:ratingleaderboard --region=eu run: bun build:ratingleaderboard --region=eu
+13
View File
@@ -25,4 +25,17 @@ jobs:
DISCORD_TOKEN: ${{ secrets.DISCORD_TOKEN }} DISCORD_TOKEN: ${{ secrets.DISCORD_TOKEN }}
DATABASE_URL: ${{ secrets.DATABASE_URL }} DATABASE_URL: ${{ secrets.DATABASE_URL }}
PUBLIC_WARGAMING_APPLICATION_ID: ${{ secrets.PUBLIC_WARGAMING_APPLICATION_ID }} PUBLIC_WARGAMING_APPLICATION_ID: ${{ secrets.PUBLIC_WARGAMING_APPLICATION_ID }}
PUBLIC_ASSET_FAST_USER: ${{ secrets.PUBLIC_ASSET_FAST_USER }}
PUBLIC_ASSET_FAST_REPO: ${{ secrets.PUBLIC_ASSET_FAST_REPO }}
PUBLIC_PROMOTE_OPENTEST: ${{ secrets.PUBLIC_PROMOTE_OPENTEST }}
ALLOW_ROBOTS: 'true'
WOTB_GLOSSARY: ${{ secrets.WOTB_GLOSSARY }}
PUBLIC_GOOGLE_TAG_MANAGER_ID: ${{ secrets.PUBLIC_GOOGLE_TAG_MANAGER_ID }}
PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID: ${{ secrets.PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID }}
GOOGLE_APPLICATION_CREDENTIALS: ${{ secrets.GOOGLE_APPLICATION_CREDENTIALS }}
WOTB_GLOSSARY_DOMAIN: ${{ secrets.WOTB_GLOSSARY_DOMAIN }}
WOTB_GLOSSARY_PATH: ${{ secrets.WOTB_GLOSSARY_PATH }}
PUBLIC_DISCORD_SERVER_ID: ${{ secrets.PUBLIC_DISCORD_SERVER_ID }}
PUBLIC_ASSET_BASE: ${{ secrets.PUBLIC_ASSET_BASE }}
PUBLIC_BRANCH: ${{ secrets.PUBLIC_BRANCH }}
run: bun build:ratingleaderboard --region=com run: bun build:ratingleaderboard --region=com
+3 -3
View File
@@ -18,10 +18,8 @@ concurrency:
env: env:
PUBLIC_WARGAMING_APPLICATION_ID: ${{ secrets.PUBLIC_WARGAMING_APPLICATION_ID }} PUBLIC_WARGAMING_APPLICATION_ID: ${{ secrets.PUBLIC_WARGAMING_APPLICATION_ID }}
PUBLIC_ASSET_REPO: ${{ secrets.PUBLIC_ASSET_REPO }}
PUBLIC_ASSET_BRANCH: ${{ secrets.PUBLIC_ASSET_BRANCH }}
PUBLIC_PROMOTE_OPENTEST: ${{ secrets.PUBLIC_PROMOTE_OPENTEST }} PUBLIC_PROMOTE_OPENTEST: ${{ secrets.PUBLIC_PROMOTE_OPENTEST }}
ALLOW_ROBOTS: "true" ALLOW_ROBOTS: ${{ secrets.ALLOW_ROBOTS }}
WOTB_GLOSSARY: ${{ secrets.WOTB_GLOSSARY }} WOTB_GLOSSARY: ${{ secrets.WOTB_GLOSSARY }}
PUBLIC_GOOGLE_TAG_MANAGER_ID: ${{ secrets.PUBLIC_GOOGLE_TAG_MANAGER_ID }} PUBLIC_GOOGLE_TAG_MANAGER_ID: ${{ secrets.PUBLIC_GOOGLE_TAG_MANAGER_ID }}
PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID: ${{ secrets.PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID }} PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID: ${{ secrets.PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID }}
@@ -29,6 +27,8 @@ env:
WOTB_GLOSSARY_DOMAIN: ${{ secrets.WOTB_GLOSSARY_DOMAIN }} WOTB_GLOSSARY_DOMAIN: ${{ secrets.WOTB_GLOSSARY_DOMAIN }}
WOTB_GLOSSARY_PATH: ${{ secrets.WOTB_GLOSSARY_PATH }} WOTB_GLOSSARY_PATH: ${{ secrets.WOTB_GLOSSARY_PATH }}
PUBLIC_DISCORD_SERVER_ID: ${{ secrets.PUBLIC_DISCORD_SERVER_ID }} PUBLIC_DISCORD_SERVER_ID: ${{ secrets.PUBLIC_DISCORD_SERVER_ID }}
PUBLIC_ASSET_BASE: ${{ secrets.PUBLIC_ASSET_BASE }}
PUBLIC_BRANCH: ${{ secrets.PUBLIC_BRANCH }}
jobs: jobs:
build: build:
+2 -3
View File
@@ -1,7 +1,7 @@
node_modules node_modules
_node_modules _node_modules
package-lock.json package-lock.json
.env *.env
/test-results/ /test-results/
/playwright-report/ /playwright-report/
/playwright/.cache/ /playwright/.cache/
@@ -22,8 +22,7 @@ depots
public/sitemap* public/sitemap*
/firebase.json /firebase.json
target target
# packages/core/src/protos/* # packages/core/src/protos/*.ts
# !packages/core/src/protos/*.proto
/.vercel /.vercel
/.astro /.astro
.vercel .vercel
+3 -3
View File
@@ -4,6 +4,6 @@
[submodule "submodules/CUE4Parse"] [submodule "submodules/CUE4Parse"]
path = submodules/CUE4Parse path = submodules/CUE4Parse
url = https://github.com/FabianFG/CUE4Parse url = https://github.com/FabianFG/CUE4Parse
[submodule "submodules/UAssetAPI"] [submodule "submodules/blitzkit-internal"]
path = submodules/UAssetAPI path = submodules/blitzkit-internal
url = https://github.com/atenfyr/UAssetAPI url = https://github.com/blitzkit/internal
+2
View File
@@ -86,6 +86,7 @@
"gameplay", "gameplay",
"glsl", "glsl",
"GLTF", "GLTF",
"gtag",
"haha", "haha",
"highp", "highp",
"iife", "iife",
@@ -108,6 +109,7 @@
"Maddoxkkm", "Maddoxkkm",
"malum", "malum",
"mantlets", "mantlets",
"mediump",
"metallicness", "metallicness",
"metalness", "metalness",
"minitelrose", "minitelrose",
Regular → Executable
BIN
View File
Binary file not shown.
+18
View File
@@ -0,0 +1,18 @@
# BlitzKit 1.27.12
This update only affects the website.
## Features
- Added the ability to sort by HE shell penetration
- The Tankopedia compare bars now account for equipment and selected shells
- Made the hero section of the Tankopedia a bit shorter to show users that the page is scrollable
## Fixes
- The "Clear filters" button no longer shows up after clearing the search bar
- Guns for some tanks no longer go transparent when far away from the camera
- The dynamic armor tab no longer lags and flickers when rotating the turret of a tank
- Reimplemented the missing tool backgrounds in the navigation bar hamburger menu
- The navigation bar now properly goes transparent for pages that request like the Tankopedia pages
- Removed the tank name text outline because it doesn't work on most devices
+19
View File
@@ -0,0 +1,19 @@
# BlitzKit 1.27.13
This update adds a feature for a future version of WoTB 👁️👃👁️
## Features
- Added compatibility for the new mechanic for the upcoming Polish Tank Destroyers
- This code will remain dormant until the update for WoTB is released
- Added a progress bar to the hero section of the Tankopedia to show that the model is loading
- Reordered some Tankopedia statistics to bring important statistics like Damage to the very top
## Fixes
- The second column in the footer is now aligned on mobile devices
- Fixed an issue that stopped the armor highlighting from working on the Kiwi browser and on older devices
## Technical Changes
- Removed permissions for robots to crawl non-blitzkit.app domains
+2 -1
View File
@@ -1,7 +1,7 @@
{ {
"name": "blitzkit", "name": "blitzkit",
"private": true, "private": true,
"version": "1.27.11", "version": "1.27.13",
"description": "🎉 Tools for everything World of Tanks Blitz", "description": "🎉 Tools for everything World of Tanks Blitz",
"type": "module", "type": "module",
"types": "./types.d.ts", "types": "./types.d.ts",
@@ -42,6 +42,7 @@
"dependencies": { "dependencies": {
"googleapis": "^144.0.0", "googleapis": "^144.0.0",
"lodash-es": "^4.17.21", "lodash-es": "^4.17.21",
"protobufjs": "^7.5.2",
"quicklime": "^1.2.0", "quicklime": "^1.2.0",
"sharp": "^0.33.5" "sharp": "^0.33.5"
}, },
+1 -8
View File
@@ -1,12 +1,5 @@
import { assertSecret } from './assertSecret'; import { assertSecret } from './assertSecret';
const repo = assertSecret(import.meta.env.PUBLIC_ASSET_REPO);
const branch = assertSecret(import.meta.env.PUBLIC_ASSET_BRANCH);
const fastUser = assertSecret(import.meta.env.PUBLIC_ASSET_FAST_USER);
const fastRepo = assertSecret(import.meta.env.PUBLIC_ASSET_FAST_REPO);
export function asset(path: string) { export function asset(path: string) {
return branch === 'main' return `${assertSecret(import.meta.env.PUBLIC_ASSET_BASE)}/${path}`;
? `https://${fastUser}.github.io/${fastRepo}/${path}`
: `https://raw.githubusercontent.com/${repo}/${branch}/${path}`;
} }
@@ -1,5 +0,0 @@
import { MessageFns } from '../protos';
export function encodePBBuffer<Type>(message: MessageFns<Type>, data: Type) {
return Buffer.from(message.encode(data).finish());
}
-1
View File
@@ -1,3 +1,2 @@
export * from './encodePBBuffer';
export * from './fetchPB'; export * from './fetchPB';
export * from './pbMap'; export * from './pbMap';
@@ -58,7 +58,7 @@ export interface Samples {
total: number; total: number;
} }
function createBaseAverageDefinitions(): AverageDefinitions { export function createBaseAverageDefinitions(): AverageDefinitions {
return { averages: {}, samples: createBaseSamples(), time: 0 }; return { averages: {}, samples: createBaseSamples(), time: 0 };
} }
@@ -174,7 +174,7 @@ export const AverageDefinitions: MessageFns<AverageDefinitions> = {
}, },
}; };
function createBaseAverageDefinitions_AveragesEntry(): AverageDefinitions_AveragesEntry { export function createBaseAverageDefinitions_AveragesEntry(): AverageDefinitions_AveragesEntry {
return { key: 0, value: createBaseAverageDefinitionsEntry() }; return { key: 0, value: createBaseAverageDefinitionsEntry() };
} }
@@ -251,12 +251,12 @@ export const AverageDefinitions_AveragesEntry: MessageFns<AverageDefinitions_Ave
message.key = object.key ?? 0; message.key = object.key ?? 0;
message.value = (object.value !== undefined && object.value !== null) message.value = (object.value !== undefined && object.value !== null)
? AverageDefinitionsEntry.fromPartial(object.value) ? AverageDefinitionsEntry.fromPartial(object.value)
: undefined; : createBaseAverageDefinitionsEntry();
return message; return message;
}, },
}; };
function createBaseAverageDefinitionsEntry(): AverageDefinitionsEntry { export function createBaseAverageDefinitionsEntry(): AverageDefinitionsEntry {
return { return {
mu: createBaseAverageDefinitionsAllStats(), mu: createBaseAverageDefinitionsAllStats(),
sigma: createBaseAverageDefinitionsAllStats(), sigma: createBaseAverageDefinitionsAllStats(),
@@ -377,7 +377,7 @@ export const AverageDefinitionsEntry: MessageFns<AverageDefinitionsEntry> = {
}, },
}; };
function createBaseAverageDefinitionsAllStats(): AverageDefinitionsAllStats { export function createBaseAverageDefinitionsAllStats(): AverageDefinitionsAllStats {
return { return {
battles: 0, battles: 0,
capture_points: 0, capture_points: 0,
@@ -738,7 +738,7 @@ export const AverageDefinitionsAllStats: MessageFns<AverageDefinitionsAllStats>
}, },
}; };
function createBaseSamples(): Samples { export function createBaseSamples(): Samples {
return { d_1: 0, d_7: 0, d_30: 0, d_60: 0, d_90: 0, d_120: 0, total: 0 }; return { d_1: 0, d_7: 0, d_30: 0, d_60: 0, d_90: 0, d_120: 0, total: 0 };
} }
@@ -6,7 +6,7 @@
/* eslint-disable */ /* eslint-disable */
import { BinaryReader, BinaryWriter } from "@bufbuild/protobuf/wire"; import { BinaryReader, BinaryWriter } from "@bufbuild/protobuf/wire";
import { I18nString, createBaseI18nString } from "./i18n"; import { createBaseI18nString, I18nString } from "./i18n";
export const protobufPackage = "blitzkit"; export const protobufPackage = "blitzkit";
@@ -26,7 +26,7 @@ export interface Camouflage {
tank_name_full?: I18nString | undefined; tank_name_full?: I18nString | undefined;
} }
function createBaseCamouflageDefinitions(): CamouflageDefinitions { export function createBaseCamouflageDefinitions(): CamouflageDefinitions {
return { camouflages: {} }; return { camouflages: {} };
} }
@@ -108,7 +108,7 @@ export const CamouflageDefinitions: MessageFns<CamouflageDefinitions> = {
}, },
}; };
function createBaseCamouflageDefinitions_CamouflagesEntry(): CamouflageDefinitions_CamouflagesEntry { export function createBaseCamouflageDefinitions_CamouflagesEntry(): CamouflageDefinitions_CamouflagesEntry {
return { key: 0, value: createBaseCamouflage() }; return { key: 0, value: createBaseCamouflage() };
} }
@@ -185,12 +185,12 @@ export const CamouflageDefinitions_CamouflagesEntry: MessageFns<CamouflageDefini
message.key = object.key ?? 0; message.key = object.key ?? 0;
message.value = (object.value !== undefined && object.value !== null) message.value = (object.value !== undefined && object.value !== null)
? Camouflage.fromPartial(object.value) ? Camouflage.fromPartial(object.value)
: undefined; : createBaseCamouflage();
return message; return message;
}, },
}; };
function createBaseCamouflage(): Camouflage { export function createBaseCamouflage(): Camouflage {
return { id: 0, name: createBaseI18nString(), tank_name: undefined, tank_name_full: undefined }; return { id: 0, name: createBaseI18nString(), tank_name: undefined, tank_name_full: undefined };
} }
@@ -6,7 +6,7 @@
/* eslint-disable */ /* eslint-disable */
import { BinaryReader, BinaryWriter } from "@bufbuild/protobuf/wire"; import { BinaryReader, BinaryWriter } from "@bufbuild/protobuf/wire";
import { I18nString, createBaseI18nString } from "./i18n"; import { createBaseI18nString, I18nString } from "./i18n";
export const protobufPackage = "blitzkit"; export const protobufPackage = "blitzkit";
@@ -82,7 +82,7 @@ export interface ConsumableTankNationFilter {
nations: string[]; nations: string[];
} }
function createBaseConsumableDefinitions(): ConsumableDefinitions { export function createBaseConsumableDefinitions(): ConsumableDefinitions {
return { consumables: {} }; return { consumables: {} };
} }
@@ -164,7 +164,7 @@ export const ConsumableDefinitions: MessageFns<ConsumableDefinitions> = {
}, },
}; };
function createBaseConsumableDefinitions_ConsumablesEntry(): ConsumableDefinitions_ConsumablesEntry { export function createBaseConsumableDefinitions_ConsumablesEntry(): ConsumableDefinitions_ConsumablesEntry {
return { key: 0, value: createBaseConsumable() }; return { key: 0, value: createBaseConsumable() };
} }
@@ -241,12 +241,12 @@ export const ConsumableDefinitions_ConsumablesEntry: MessageFns<ConsumableDefini
message.key = object.key ?? 0; message.key = object.key ?? 0;
message.value = (object.value !== undefined && object.value !== null) message.value = (object.value !== undefined && object.value !== null)
? Consumable.fromPartial(object.value) ? Consumable.fromPartial(object.value)
: undefined; : createBaseConsumable();
return message; return message;
}, },
}; };
function createBaseConsumable(): Consumable { export function createBaseConsumable(): Consumable {
return { return {
id: 0, id: 0,
name: createBaseI18nString(), name: createBaseI18nString(),
@@ -416,7 +416,7 @@ export const Consumable: MessageFns<Consumable> = {
}, },
}; };
function createBaseConsumableTankFilter(): ConsumableTankFilter { export function createBaseConsumableTankFilter(): ConsumableTankFilter {
return { filter_type: undefined }; return { filter_type: undefined };
} }
@@ -564,7 +564,7 @@ export const ConsumableTankFilter: MessageFns<ConsumableTankFilter> = {
}, },
}; };
function createBaseConsumableTankTierFilter(): ConsumableTankTierFilter { export function createBaseConsumableTankTierFilter(): ConsumableTankTierFilter {
return { min: 0, max: 0 }; return { min: 0, max: 0 };
} }
@@ -640,7 +640,7 @@ export const ConsumableTankTierFilter: MessageFns<ConsumableTankTierFilter> = {
}, },
}; };
function createBaseConsumableTankIdsFilter(): ConsumableTankIdsFilter { export function createBaseConsumableTankIdsFilter(): ConsumableTankIdsFilter {
return { ids: [] }; return { ids: [] };
} }
@@ -710,7 +710,7 @@ export const ConsumableTankIdsFilter: MessageFns<ConsumableTankIdsFilter> = {
}, },
}; };
function createBaseConsumableTankCategoryFilter(): ConsumableTankCategoryFilter { export function createBaseConsumableTankCategoryFilter(): ConsumableTankCategoryFilter {
return { categories: [] }; return { categories: [] };
} }
@@ -784,7 +784,7 @@ export const ConsumableTankCategoryFilter: MessageFns<ConsumableTankCategoryFilt
}, },
}; };
function createBaseConsumableTankNationFilter(): ConsumableTankNationFilter { export function createBaseConsumableTankNationFilter(): ConsumableTankNationFilter {
return { nations: [] }; return { nations: [] };
} }
@@ -6,7 +6,7 @@
/* eslint-disable */ /* eslint-disable */
import { BinaryReader, BinaryWriter } from "@bufbuild/protobuf/wire"; import { BinaryReader, BinaryWriter } from "@bufbuild/protobuf/wire";
import { I18nString, createBaseI18nString } from "./i18n"; import { createBaseI18nString, I18nString } from "./i18n";
export const protobufPackage = "blitzkit"; export const protobufPackage = "blitzkit";
@@ -39,7 +39,7 @@ export interface EquipmentSlot {
right: number; right: number;
} }
function createBaseEquipmentDefinitions(): EquipmentDefinitions { export function createBaseEquipmentDefinitions(): EquipmentDefinitions {
return { presets: {}, equipments: {} }; return { presets: {}, equipments: {} };
} }
@@ -159,7 +159,7 @@ export const EquipmentDefinitions: MessageFns<EquipmentDefinitions> = {
}, },
}; };
function createBaseEquipmentDefinitions_PresetsEntry(): EquipmentDefinitions_PresetsEntry { export function createBaseEquipmentDefinitions_PresetsEntry(): EquipmentDefinitions_PresetsEntry {
return { key: "", value: createBaseEquipmentPreset() }; return { key: "", value: createBaseEquipmentPreset() };
} }
@@ -236,12 +236,12 @@ export const EquipmentDefinitions_PresetsEntry: MessageFns<EquipmentDefinitions_
message.key = object.key ?? ""; message.key = object.key ?? "";
message.value = (object.value !== undefined && object.value !== null) message.value = (object.value !== undefined && object.value !== null)
? EquipmentPreset.fromPartial(object.value) ? EquipmentPreset.fromPartial(object.value)
: undefined; : createBaseEquipmentPreset();
return message; return message;
}, },
}; };
function createBaseEquipmentDefinitions_EquipmentsEntry(): EquipmentDefinitions_EquipmentsEntry { export function createBaseEquipmentDefinitions_EquipmentsEntry(): EquipmentDefinitions_EquipmentsEntry {
return { key: 0, value: createBaseEquipment() }; return { key: 0, value: createBaseEquipment() };
} }
@@ -318,12 +318,12 @@ export const EquipmentDefinitions_EquipmentsEntry: MessageFns<EquipmentDefinitio
message.key = object.key ?? 0; message.key = object.key ?? 0;
message.value = (object.value !== undefined && object.value !== null) message.value = (object.value !== undefined && object.value !== null)
? Equipment.fromPartial(object.value) ? Equipment.fromPartial(object.value)
: undefined; : createBaseEquipment();
return message; return message;
}, },
}; };
function createBaseEquipment(): Equipment { export function createBaseEquipment(): Equipment {
return { name: createBaseI18nString(), description: createBaseI18nString() }; return { name: createBaseI18nString(), description: createBaseI18nString() };
} }
@@ -403,7 +403,7 @@ export const Equipment: MessageFns<Equipment> = {
}, },
}; };
function createBaseEquipmentPreset(): EquipmentPreset { export function createBaseEquipmentPreset(): EquipmentPreset {
return { slots: [] }; return { slots: [] };
} }
@@ -463,7 +463,7 @@ export const EquipmentPreset: MessageFns<EquipmentPreset> = {
}, },
}; };
function createBaseEquipmentSlot(): EquipmentSlot { export function createBaseEquipmentSlot(): EquipmentSlot {
return { left: 0, right: 0 }; return { left: 0, right: 0 };
} }
+32 -60
View File
@@ -5,10 +5,10 @@
// source: packages/core/src/protos/gallery.proto // source: packages/core/src/protos/gallery.proto
/* eslint-disable */ /* eslint-disable */
import { BinaryReader, BinaryWriter } from '@bufbuild/protobuf/wire'; import { BinaryReader, BinaryWriter } from "@bufbuild/protobuf/wire";
import { I18nString, createBaseI18nString } from './i18n'; import { createBaseI18nString, I18nString } from "./i18n";
export const protobufPackage = 'blitzkit'; export const protobufPackage = "blitzkit";
export interface Gallery { export interface Gallery {
avatars: Avatar[]; avatars: Avatar[];
@@ -20,15 +20,12 @@ export interface Avatar {
extension: string; extension: string;
} }
function createBaseGallery(): Gallery { export function createBaseGallery(): Gallery {
return { avatars: [] }; return { avatars: [] };
} }
export const Gallery: MessageFns<Gallery> = { export const Gallery: MessageFns<Gallery> = {
encode( encode(message: Gallery, writer: BinaryWriter = new BinaryWriter()): BinaryWriter {
message: Gallery,
writer: BinaryWriter = new BinaryWriter(),
): BinaryWriter {
for (const v of message.avatars) { for (const v of message.avatars) {
Avatar.encode(v!, writer.uint32(10).fork()).join(); Avatar.encode(v!, writer.uint32(10).fork()).join();
} }
@@ -36,8 +33,7 @@ export const Gallery: MessageFns<Gallery> = {
}, },
decode(input: BinaryReader | Uint8Array, length?: number): Gallery { decode(input: BinaryReader | Uint8Array, length?: number): Gallery {
const reader = const reader = input instanceof BinaryReader ? input : new BinaryReader(input);
input instanceof BinaryReader ? input : new BinaryReader(input);
let end = length === undefined ? reader.len : reader.pos + length; let end = length === undefined ? reader.len : reader.pos + length;
const message = createBaseGallery(); const message = createBaseGallery();
while (reader.pos < end) { while (reader.pos < end) {
@@ -62,9 +58,7 @@ export const Gallery: MessageFns<Gallery> = {
fromJSON(object: any): Gallery { fromJSON(object: any): Gallery {
return { return {
avatars: globalThis.Array.isArray(object?.avatars) avatars: globalThis.Array.isArray(object?.avatars) ? object.avatars.map((e: any) => Avatar.fromJSON(e)) : [],
? object.avatars.map((e: any) => Avatar.fromJSON(e))
: [],
}; };
}, },
@@ -86,30 +80,26 @@ export const Gallery: MessageFns<Gallery> = {
}, },
}; };
function createBaseAvatar(): Avatar { export function createBaseAvatar(): Avatar {
return { id: '', name: createBaseI18nString(), extension: '' }; return { id: "", name: createBaseI18nString(), extension: "" };
} }
export const Avatar: MessageFns<Avatar> = { export const Avatar: MessageFns<Avatar> = {
encode( encode(message: Avatar, writer: BinaryWriter = new BinaryWriter()): BinaryWriter {
message: Avatar, if (message.id !== "") {
writer: BinaryWriter = new BinaryWriter(),
): BinaryWriter {
if (message.id !== '') {
writer.uint32(10).string(message.id); writer.uint32(10).string(message.id);
} }
if (message.name !== undefined) { if (message.name !== undefined) {
I18nString.encode(message.name, writer.uint32(18).fork()).join(); I18nString.encode(message.name, writer.uint32(18).fork()).join();
} }
if (message.extension !== '') { if (message.extension !== "") {
writer.uint32(26).string(message.extension); writer.uint32(26).string(message.extension);
} }
return writer; return writer;
}, },
decode(input: BinaryReader | Uint8Array, length?: number): Avatar { decode(input: BinaryReader | Uint8Array, length?: number): Avatar {
const reader = const reader = input instanceof BinaryReader ? input : new BinaryReader(input);
input instanceof BinaryReader ? input : new BinaryReader(input);
let end = length === undefined ? reader.len : reader.pos + length; let end = length === undefined ? reader.len : reader.pos + length;
const message = createBaseAvatar(); const message = createBaseAvatar();
while (reader.pos < end) { while (reader.pos < end) {
@@ -150,23 +140,21 @@ export const Avatar: MessageFns<Avatar> = {
fromJSON(object: any): Avatar { fromJSON(object: any): Avatar {
return { return {
id: globalThis.String(assertSet('Avatar.id', object.id)), id: globalThis.String(assertSet("Avatar.id", object.id)),
name: I18nString.fromJSON(assertSet('Avatar.name', object.name)), name: I18nString.fromJSON(assertSet("Avatar.name", object.name)),
extension: globalThis.String( extension: globalThis.String(assertSet("Avatar.extension", object.extension)),
assertSet('Avatar.extension', object.extension),
),
}; };
}, },
toJSON(message: Avatar): unknown { toJSON(message: Avatar): unknown {
const obj: any = {}; const obj: any = {};
if (message.id !== '') { if (message.id !== "") {
obj.id = message.id; obj.id = message.id;
} }
if (message.name !== undefined) { if (message.name !== undefined) {
obj.name = I18nString.toJSON(message.name); obj.name = I18nString.toJSON(message.name);
} }
if (message.extension !== '') { if (message.extension !== "") {
obj.extension = message.extension; obj.extension = message.extension;
} }
return obj; return obj;
@@ -177,43 +165,27 @@ export const Avatar: MessageFns<Avatar> = {
}, },
fromPartial<I extends Exact<DeepPartial<Avatar>, I>>(object: I): Avatar { fromPartial<I extends Exact<DeepPartial<Avatar>, I>>(object: I): Avatar {
const message = createBaseAvatar(); const message = createBaseAvatar();
message.id = object.id ?? ''; message.id = object.id ?? "";
message.name = message.name = (object.name !== undefined && object.name !== null)
object.name !== undefined && object.name !== null ? I18nString.fromPartial(object.name)
? I18nString.fromPartial(object.name) : createBaseI18nString();
: createBaseI18nString(); message.extension = object.extension ?? "";
message.extension = object.extension ?? '';
return message; return message;
}, },
}; };
type Builtin = type Builtin = Date | Function | Uint8Array | string | number | boolean | undefined;
| Date
| Function
| Uint8Array
| string
| number
| boolean
| undefined;
export type DeepPartial<T> = T extends Builtin export type DeepPartial<T> = T extends Builtin ? T
? T : T extends globalThis.Array<infer U> ? globalThis.Array<DeepPartial<U>>
: T extends globalThis.Array<infer U> : T extends ReadonlyArray<infer U> ? ReadonlyArray<DeepPartial<U>>
? globalThis.Array<DeepPartial<U>> : T extends { $case: string; value: unknown } ? { $case: T["$case"]; value?: DeepPartial<T["value"]> }
: T extends ReadonlyArray<infer U> : T extends {} ? { [K in keyof T]?: DeepPartial<T[K]> }
? ReadonlyArray<DeepPartial<U>> : Partial<T>;
: T extends { $case: string; value: unknown }
? { $case: T['$case']; value?: DeepPartial<T['value']> }
: T extends {}
? { [K in keyof T]?: DeepPartial<T[K]> }
: Partial<T>;
type KeysOfUnion<T> = T extends T ? keyof T : never; type KeysOfUnion<T> = T extends T ? keyof T : never;
export type Exact<P, I extends P> = P extends Builtin export type Exact<P, I extends P> = P extends Builtin ? P
? P : P & { [K in keyof P]: Exact<P[K], I[K]> } & { [K in Exclude<keyof I, KeysOfUnion<P>>]: never };
: P & { [K in keyof P]: Exact<P[K], I[K]> } & {
[K in Exclude<keyof I, KeysOfUnion<P>>]: never;
};
function isSet(value: any): boolean { function isSet(value: any): boolean {
return value !== null && value !== undefined; return value !== null && value !== undefined;
+8 -8
View File
@@ -6,7 +6,7 @@
/* eslint-disable */ /* eslint-disable */
import { BinaryReader, BinaryWriter } from "@bufbuild/protobuf/wire"; import { BinaryReader, BinaryWriter } from "@bufbuild/protobuf/wire";
import { I18nString, createBaseI18nString } from "./i18n"; import { createBaseI18nString, I18nString } from "./i18n";
export const protobufPackage = "blitzkit"; export const protobufPackage = "blitzkit";
@@ -36,7 +36,7 @@ export interface GameModeRole {
consumables: number[]; consumables: number[];
} }
function createBaseGameDefinitions(): GameDefinitions { export function createBaseGameDefinitions(): GameDefinitions {
return { version: "", nations: [], gameModes: {}, roles: {} }; return { version: "", nations: [], gameModes: {}, roles: {} };
} }
@@ -185,7 +185,7 @@ export const GameDefinitions: MessageFns<GameDefinitions> = {
}, },
}; };
function createBaseGameDefinitions_GameModesEntry(): GameDefinitions_GameModesEntry { export function createBaseGameDefinitions_GameModesEntry(): GameDefinitions_GameModesEntry {
return { key: 0, value: createBaseGameMode() }; return { key: 0, value: createBaseGameMode() };
} }
@@ -260,12 +260,12 @@ export const GameDefinitions_GameModesEntry: MessageFns<GameDefinitions_GameMode
message.key = object.key ?? 0; message.key = object.key ?? 0;
message.value = (object.value !== undefined && object.value !== null) message.value = (object.value !== undefined && object.value !== null)
? GameMode.fromPartial(object.value) ? GameMode.fromPartial(object.value)
: undefined; : createBaseGameMode();
return message; return message;
}, },
}; };
function createBaseGameDefinitions_RolesEntry(): GameDefinitions_RolesEntry { export function createBaseGameDefinitions_RolesEntry(): GameDefinitions_RolesEntry {
return { key: 0, value: createBaseGameModeRole() }; return { key: 0, value: createBaseGameModeRole() };
} }
@@ -338,12 +338,12 @@ export const GameDefinitions_RolesEntry: MessageFns<GameDefinitions_RolesEntry>
message.key = object.key ?? 0; message.key = object.key ?? 0;
message.value = (object.value !== undefined && object.value !== null) message.value = (object.value !== undefined && object.value !== null)
? GameModeRole.fromPartial(object.value) ? GameModeRole.fromPartial(object.value)
: undefined; : createBaseGameModeRole();
return message; return message;
}, },
}; };
function createBaseGameMode(): GameMode { export function createBaseGameMode(): GameMode {
return { name: createBaseI18nString() }; return { name: createBaseI18nString() };
} }
@@ -403,7 +403,7 @@ export const GameMode: MessageFns<GameMode> = {
}, },
}; };
function createBaseGameModeRole(): GameModeRole { export function createBaseGameModeRole(): GameModeRole {
return { provisions: [], consumables: [] }; return { provisions: [], consumables: [] };
} }
+1 -1
View File
@@ -97,7 +97,7 @@ export const I18nString: MessageFns<I18nString> = {
}, },
}; };
function createBaseI18nString_LocalesEntry(): I18nString_LocalesEntry { export function createBaseI18nString_LocalesEntry(): I18nString_LocalesEntry {
return { key: "", value: "" }; return { key: "", value: "" };
} }
+5 -5
View File
@@ -6,7 +6,7 @@
/* eslint-disable */ /* eslint-disable */
import { BinaryReader, BinaryWriter } from "@bufbuild/protobuf/wire"; import { BinaryReader, BinaryWriter } from "@bufbuild/protobuf/wire";
import { I18nString, createBaseI18nString } from "./i18n"; import { createBaseI18nString, I18nString } from "./i18n";
export const protobufPackage = "blitzkit"; export const protobufPackage = "blitzkit";
@@ -24,7 +24,7 @@ export interface MapDefinition {
name: I18nString; name: I18nString;
} }
function createBaseMapDefinitions(): MapDefinitions { export function createBaseMapDefinitions(): MapDefinitions {
return { maps: {} }; return { maps: {} };
} }
@@ -103,7 +103,7 @@ export const MapDefinitions: MessageFns<MapDefinitions> = {
}, },
}; };
function createBaseMapDefinitions_MapsEntry(): MapDefinitions_MapsEntry { export function createBaseMapDefinitions_MapsEntry(): MapDefinitions_MapsEntry {
return { key: 0, value: createBaseMapDefinition() }; return { key: 0, value: createBaseMapDefinition() };
} }
@@ -176,12 +176,12 @@ export const MapDefinitions_MapsEntry: MessageFns<MapDefinitions_MapsEntry> = {
message.key = object.key ?? 0; message.key = object.key ?? 0;
message.value = (object.value !== undefined && object.value !== null) message.value = (object.value !== undefined && object.value !== null)
? MapDefinition.fromPartial(object.value) ? MapDefinition.fromPartial(object.value)
: undefined; : createBaseMapDefinition();
return message; return message;
}, },
}; };
function createBaseMapDefinition(): MapDefinition { export function createBaseMapDefinition(): MapDefinition {
return { id: 0, name: createBaseI18nString() }; return { id: 0, name: createBaseI18nString() };
} }
+21 -21
View File
@@ -110,7 +110,7 @@ export interface PitchLimitsExtrema {
range: number; range: number;
} }
function createBaseModelDefinitions(): ModelDefinitions { export function createBaseModelDefinitions(): ModelDefinitions {
return { models: {} }; return { models: {} };
} }
@@ -192,7 +192,7 @@ export const ModelDefinitions: MessageFns<ModelDefinitions> = {
}, },
}; };
function createBaseModelDefinitions_ModelsEntry(): ModelDefinitions_ModelsEntry { export function createBaseModelDefinitions_ModelsEntry(): ModelDefinitions_ModelsEntry {
return { key: 0, value: createBaseModelDefinition() }; return { key: 0, value: createBaseModelDefinition() };
} }
@@ -265,12 +265,12 @@ export const ModelDefinitions_ModelsEntry: MessageFns<ModelDefinitions_ModelsEnt
message.key = object.key ?? 0; message.key = object.key ?? 0;
message.value = (object.value !== undefined && object.value !== null) message.value = (object.value !== undefined && object.value !== null)
? ModelDefinition.fromPartial(object.value) ? ModelDefinition.fromPartial(object.value)
: undefined; : createBaseModelDefinition();
return message; return message;
}, },
}; };
function createBaseModelDefinition(): ModelDefinition { export function createBaseModelDefinition(): ModelDefinition {
return { return {
armor: createBaseArmor(), armor: createBaseArmor(),
turret_origin: createBaseVector3(), turret_origin: createBaseVector3(),
@@ -472,7 +472,7 @@ export const ModelDefinition: MessageFns<ModelDefinition> = {
}, },
}; };
function createBaseModelDefinition_TurretsEntry(): ModelDefinition_TurretsEntry { export function createBaseModelDefinition_TurretsEntry(): ModelDefinition_TurretsEntry {
return { key: 0, value: createBaseTurretModelDefinition() }; return { key: 0, value: createBaseTurretModelDefinition() };
} }
@@ -545,12 +545,12 @@ export const ModelDefinition_TurretsEntry: MessageFns<ModelDefinition_TurretsEnt
message.key = object.key ?? 0; message.key = object.key ?? 0;
message.value = (object.value !== undefined && object.value !== null) message.value = (object.value !== undefined && object.value !== null)
? TurretModelDefinition.fromPartial(object.value) ? TurretModelDefinition.fromPartial(object.value)
: undefined; : createBaseTurretModelDefinition();
return message; return message;
}, },
}; };
function createBaseModelDefinition_TracksEntry(): ModelDefinition_TracksEntry { export function createBaseModelDefinition_TracksEntry(): ModelDefinition_TracksEntry {
return { key: 0, value: createBaseTrackModelDefinition() }; return { key: 0, value: createBaseTrackModelDefinition() };
} }
@@ -623,12 +623,12 @@ export const ModelDefinition_TracksEntry: MessageFns<ModelDefinition_TracksEntry
message.key = object.key ?? 0; message.key = object.key ?? 0;
message.value = (object.value !== undefined && object.value !== null) message.value = (object.value !== undefined && object.value !== null)
? TrackModelDefinition.fromPartial(object.value) ? TrackModelDefinition.fromPartial(object.value)
: undefined; : createBaseTrackModelDefinition();
return message; return message;
}, },
}; };
function createBaseArmor(): Armor { export function createBaseArmor(): Armor {
return { thickness: {}, spaced: [] }; return { thickness: {}, spaced: [] };
} }
@@ -738,7 +738,7 @@ export const Armor: MessageFns<Armor> = {
}, },
}; };
function createBaseArmor_ThicknessEntry(): Armor_ThicknessEntry { export function createBaseArmor_ThicknessEntry(): Armor_ThicknessEntry {
return { key: 0, value: 0 }; return { key: 0, value: 0 };
} }
@@ -814,7 +814,7 @@ export const Armor_ThicknessEntry: MessageFns<Armor_ThicknessEntry> = {
}, },
}; };
function createBaseVector3(): Vector3 { export function createBaseVector3(): Vector3 {
return { x: 0, y: 0, z: 0 }; return { x: 0, y: 0, z: 0 };
} }
@@ -906,7 +906,7 @@ export const Vector3: MessageFns<Vector3> = {
}, },
}; };
function createBaseInitialTurretRotation(): InitialTurretRotation { export function createBaseInitialTurretRotation(): InitialTurretRotation {
return { yaw: 0, pitch: 0, roll: 0 }; return { yaw: 0, pitch: 0, roll: 0 };
} }
@@ -998,7 +998,7 @@ export const InitialTurretRotation: MessageFns<InitialTurretRotation> = {
}, },
}; };
function createBaseTurretModelDefinition(): TurretModelDefinition { export function createBaseTurretModelDefinition(): TurretModelDefinition {
return { return {
bounding_box: createBaseBoundingBox(), bounding_box: createBaseBoundingBox(),
armor: createBaseArmor(), armor: createBaseArmor(),
@@ -1173,7 +1173,7 @@ export const TurretModelDefinition: MessageFns<TurretModelDefinition> = {
}, },
}; };
function createBaseTurretModelDefinition_GunsEntry(): TurretModelDefinition_GunsEntry { export function createBaseTurretModelDefinition_GunsEntry(): TurretModelDefinition_GunsEntry {
return { key: 0, value: createBaseGunModelDefinition() }; return { key: 0, value: createBaseGunModelDefinition() };
} }
@@ -1248,12 +1248,12 @@ export const TurretModelDefinition_GunsEntry: MessageFns<TurretModelDefinition_G
message.key = object.key ?? 0; message.key = object.key ?? 0;
message.value = (object.value !== undefined && object.value !== null) message.value = (object.value !== undefined && object.value !== null)
? GunModelDefinition.fromPartial(object.value) ? GunModelDefinition.fromPartial(object.value)
: undefined; : createBaseGunModelDefinition();
return message; return message;
}, },
}; };
function createBaseYawLimits(): YawLimits { export function createBaseYawLimits(): YawLimits {
return { min: 0, max: 0 }; return { min: 0, max: 0 };
} }
@@ -1329,7 +1329,7 @@ export const YawLimits: MessageFns<YawLimits> = {
}, },
}; };
function createBaseBoundingBox(): BoundingBox { export function createBaseBoundingBox(): BoundingBox {
return { min: createBaseVector3(), max: createBaseVector3() }; return { min: createBaseVector3(), max: createBaseVector3() };
} }
@@ -1409,7 +1409,7 @@ export const BoundingBox: MessageFns<BoundingBox> = {
}, },
}; };
function createBaseTrackModelDefinition(): TrackModelDefinition { export function createBaseTrackModelDefinition(): TrackModelDefinition {
return { thickness: 0, origin: createBaseVector3() }; return { thickness: 0, origin: createBaseVector3() };
} }
@@ -1487,7 +1487,7 @@ export const TrackModelDefinition: MessageFns<TrackModelDefinition> = {
}, },
}; };
function createBaseGunModelDefinition(): GunModelDefinition { export function createBaseGunModelDefinition(): GunModelDefinition {
return { armor: createBaseArmor(), thickness: 0, model_id: 0, pitch: createBasePitchLimits(), mask: undefined }; return { armor: createBaseArmor(), thickness: 0, model_id: 0, pitch: createBasePitchLimits(), mask: undefined };
} }
@@ -1615,7 +1615,7 @@ export const GunModelDefinition: MessageFns<GunModelDefinition> = {
}, },
}; };
function createBasePitchLimits(): PitchLimits { export function createBasePitchLimits(): PitchLimits {
return { min: 0, max: 0, front: undefined, back: undefined, transition: undefined }; return { min: 0, max: 0, front: undefined, back: undefined, transition: undefined };
} }
@@ -1743,7 +1743,7 @@ export const PitchLimits: MessageFns<PitchLimits> = {
}, },
}; };
function createBasePitchLimitsExtrema(): PitchLimitsExtrema { export function createBasePitchLimitsExtrema(): PitchLimitsExtrema {
return { min: 0, max: 0, range: 0 }; return { min: 0, max: 0, range: 0 };
} }
+2 -2
View File
@@ -19,7 +19,7 @@ export interface PopularTank {
views: number; views: number;
} }
function createBasePopularTanks(): PopularTanks { export function createBasePopularTanks(): PopularTanks {
return { tanks: [] }; return { tanks: [] };
} }
@@ -79,7 +79,7 @@ export const PopularTanks: MessageFns<PopularTanks> = {
}, },
}; };
function createBasePopularTank(): PopularTank { export function createBasePopularTank(): PopularTank {
return { id: 0, views: 0 }; return { id: 0, views: 0 };
} }
@@ -7,7 +7,7 @@
/* eslint-disable */ /* eslint-disable */
import { BinaryReader, BinaryWriter } from "@bufbuild/protobuf/wire"; import { BinaryReader, BinaryWriter } from "@bufbuild/protobuf/wire";
import { ConsumableTankFilter } from "./consumable_definitions"; import { ConsumableTankFilter } from "./consumable_definitions";
import { I18nString, createBaseI18nString } from "./i18n"; import { createBaseI18nString, I18nString } from "./i18n";
export const protobufPackage = "blitzkit"; export const protobufPackage = "blitzkit";
@@ -29,7 +29,7 @@ export interface Provision {
exclude: ConsumableTankFilter[]; exclude: ConsumableTankFilter[];
} }
function createBaseProvisionDefinitions(): ProvisionDefinitions { export function createBaseProvisionDefinitions(): ProvisionDefinitions {
return { provisions: {} }; return { provisions: {} };
} }
@@ -111,7 +111,7 @@ export const ProvisionDefinitions: MessageFns<ProvisionDefinitions> = {
}, },
}; };
function createBaseProvisionDefinitions_ProvisionsEntry(): ProvisionDefinitions_ProvisionsEntry { export function createBaseProvisionDefinitions_ProvisionsEntry(): ProvisionDefinitions_ProvisionsEntry {
return { key: 0, value: createBaseProvision() }; return { key: 0, value: createBaseProvision() };
} }
@@ -188,12 +188,12 @@ export const ProvisionDefinitions_ProvisionsEntry: MessageFns<ProvisionDefinitio
message.key = object.key ?? 0; message.key = object.key ?? 0;
message.value = (object.value !== undefined && object.value !== null) message.value = (object.value !== undefined && object.value !== null)
? Provision.fromPartial(object.value) ? Provision.fromPartial(object.value)
: undefined; : createBaseProvision();
return message; return message;
}, },
}; };
function createBaseProvision(): Provision { export function createBaseProvision(): Provision {
return { id: 0, name: createBaseI18nString(), crew: undefined, game_mode_exclusive: false, include: [], exclude: [] }; return { id: 0, name: createBaseI18nString(), crew: undefined, game_mode_exclusive: false, include: [], exclude: [] };
} }
@@ -36,7 +36,7 @@ export interface RatingLeaderboardEntryV2 {
kills: number; kills: number;
} }
function createBaseRatingLeaderboard(): RatingLeaderboard { export function createBaseRatingLeaderboard(): RatingLeaderboard {
return { version: undefined }; return { version: undefined };
} }
@@ -121,7 +121,7 @@ export const RatingLeaderboard: MessageFns<RatingLeaderboard> = {
}, },
}; };
function createBaseRatingLeaderboardV1(): RatingLeaderboardV1 { export function createBaseRatingLeaderboardV1(): RatingLeaderboardV1 {
return { entries: [] }; return { entries: [] };
} }
@@ -183,7 +183,7 @@ export const RatingLeaderboardV1: MessageFns<RatingLeaderboardV1> = {
}, },
}; };
function createBaseRatingLeaderboardEntryV1(): RatingLeaderboardEntryV1 { export function createBaseRatingLeaderboardEntryV1(): RatingLeaderboardEntryV1 {
return { id: 0, score: 0 }; return { id: 0, score: 0 };
} }
@@ -259,7 +259,7 @@ export const RatingLeaderboardEntryV1: MessageFns<RatingLeaderboardEntryV1> = {
}, },
}; };
function createBaseRatingLeaderboardV2(): RatingLeaderboardV2 { export function createBaseRatingLeaderboardV2(): RatingLeaderboardV2 {
return { entries: [] }; return { entries: [] };
} }
@@ -321,7 +321,7 @@ export const RatingLeaderboardV2: MessageFns<RatingLeaderboardV2> = {
}, },
}; };
function createBaseRatingLeaderboardEntryV2(): RatingLeaderboardEntryV2 { export function createBaseRatingLeaderboardEntryV2(): RatingLeaderboardEntryV2 {
return { id: 0, score: 0, battles: 0, wins: 0, survived: 0, damage: 0, kills: 0 }; return { id: 0, score: 0, battles: 0, wins: 0, survived: 0, damage: 0, kills: 0 };
} }
+5 -5
View File
@@ -28,7 +28,7 @@ export interface Video {
author: string; author: string;
} }
function createBaseReviews(): Reviews { export function createBaseReviews(): Reviews {
return { reviews: {} }; return { reviews: {} };
} }
@@ -107,7 +107,7 @@ export const Reviews: MessageFns<Reviews> = {
}, },
}; };
function createBaseReviews_ReviewsEntry(): Reviews_ReviewsEntry { export function createBaseReviews_ReviewsEntry(): Reviews_ReviewsEntry {
return { key: 0, value: createBaseReview() }; return { key: 0, value: createBaseReview() };
} }
@@ -180,12 +180,12 @@ export const Reviews_ReviewsEntry: MessageFns<Reviews_ReviewsEntry> = {
message.key = object.key ?? 0; message.key = object.key ?? 0;
message.value = (object.value !== undefined && object.value !== null) message.value = (object.value !== undefined && object.value !== null)
? Review.fromPartial(object.value) ? Review.fromPartial(object.value)
: undefined; : createBaseReview();
return message; return message;
}, },
}; };
function createBaseReview(): Review { export function createBaseReview(): Review {
return { last_updated: 0, videos: [] }; return { last_updated: 0, videos: [] };
} }
@@ -261,7 +261,7 @@ export const Review: MessageFns<Review> = {
}, },
}; };
function createBaseVideo(): Video { export function createBaseVideo(): Video {
return { id: "", author: "" }; return { id: "", author: "" };
} }
@@ -23,7 +23,7 @@ export interface Skill {
skills: string[]; skills: string[];
} }
function createBaseSkillDefinitions(): SkillDefinitions { export function createBaseSkillDefinitions(): SkillDefinitions {
return { classes: {} }; return { classes: {} };
} }
@@ -102,7 +102,7 @@ export const SkillDefinitions: MessageFns<SkillDefinitions> = {
}, },
}; };
function createBaseSkillDefinitions_ClassesEntry(): SkillDefinitions_ClassesEntry { export function createBaseSkillDefinitions_ClassesEntry(): SkillDefinitions_ClassesEntry {
return { key: 0, value: createBaseSkill() }; return { key: 0, value: createBaseSkill() };
} }
@@ -175,12 +175,14 @@ export const SkillDefinitions_ClassesEntry: MessageFns<SkillDefinitions_ClassesE
): SkillDefinitions_ClassesEntry { ): SkillDefinitions_ClassesEntry {
const message = createBaseSkillDefinitions_ClassesEntry(); const message = createBaseSkillDefinitions_ClassesEntry();
message.key = object.key ?? 0; message.key = object.key ?? 0;
message.value = (object.value !== undefined && object.value !== null) ? Skill.fromPartial(object.value) : undefined; message.value = (object.value !== undefined && object.value !== null)
? Skill.fromPartial(object.value)
: createBaseSkill();
return message; return message;
}, },
}; };
function createBaseSkill(): Skill { export function createBaseSkill(): Skill {
return { skills: [] }; return { skills: [] };
} }
@@ -157,6 +157,17 @@ message GunDefinitionBase {
required float dispersion_damaged = 13; required float dispersion_damaged = 13;
repeated Unlock unlocks = 14; repeated Unlock unlocks = 14;
required uint32 shell_capacity = 15; required uint32 shell_capacity = 15;
optional AssaultRanges assault_ranges = 16;
}
message AssaultRanges {
repeated AssaultRange ranges = 1;
repeated ShellType types = 2;
}
message AssaultRange {
required float distance = 1;
required float factor = 2;
} }
message ShellDefinition { message ShellDefinition {
File diff suppressed because it is too large. Load diff
+6 -1
View File
@@ -790,6 +790,7 @@
"fire.caliber": "caliber", "fire.caliber": "caliber",
"fire.standardPenetration": "standard penetration", "fire.standardPenetration": "standard penetration",
"fire.premiumPenetration": "premium penetration", "fire.premiumPenetration": "premium penetration",
"fire.tertiaryPenetration": "tertiary penetration",
"fire.damage": "damage", "fire.damage": "damage",
"fire.moduleDamage": "module damage", "fire.moduleDamage": "module damage",
"fire.shellVelocity": "shell velocity", "fire.shellVelocity": "shell velocity",
@@ -886,6 +887,10 @@
"tank_seo_description": "%s1 armor, statistics, equipment, provisions, and more. %s2 DPM, %s3hp alpha, %s4mm penetration, %s5kph top speed, %s6hp health.", "tank_seo_description": "%s1 armor, statistics, equipment, provisions, and more. %s2 DPM, %s3hp alpha, %s4mm penetration, %s5kph top speed, %s6hp health.",
"visualizers": { "visualizers": {
"assault": {
"title": "Assault shells"
},
"rotator": { "rotator": {
"hull": "Hull", "hull": "Hull",
"turret": "Turret", "turret": "Turret",
@@ -1078,7 +1083,6 @@
"hull_traverse_speed": "Hull traverse speed", "hull_traverse_speed": "Hull traverse speed",
"camouflage": "Camouflage", "camouflage": "Camouflage",
"reload": "Reload", "reload": "Reload",
"crewCount": "Crew count", "crewCount": "Crew count",
"shellNormalization": "Normalization", "shellNormalization": "Normalization",
"shellRicochet": "Ricochet", "shellRicochet": "Ricochet",
@@ -1092,6 +1096,7 @@
"caliber": "Caliber", "caliber": "Caliber",
"penetration": "Penetration", "penetration": "Penetration",
"damage": "Damage", "damage": "Damage",
"damageWithoutAssault": "Damage without assault shells",
"clipDamage": "Clipping potential", "clipDamage": "Clipping potential",
"moduleDamage": "Module damage", "moduleDamage": "Module damage",
"explosionRadius": "Explosion radius", "explosionRadius": "Explosion radius",
+47 -2
View File
@@ -10,7 +10,9 @@
"mm": "%s1mm", "mm": "%s1mm",
"deg": "%s1°", "deg": "%s1°",
"hp": "%s1pv", "hp": "%s1pv",
"x": "x%s1" "x": "x%s1",
"percentage": "%s1%",
"deg_s": "%s1°/s"
}, },
"gun_types": { "gun_types": {
"auto_loader": "Auto cargador", "auto_loader": "Auto cargador",
@@ -651,6 +653,10 @@
} }
}, },
"website": { "website": {
"redirect": {
"title": "301: moved permanently",
"body": "This page has moved. Redirecting..."
},
"settings": { "settings": {
"dev_mode": "Modo de desarrollador", "dev_mode": "Modo de desarrollador",
"language": "Idioma" "language": "Idioma"
@@ -692,6 +698,7 @@
"fire.caliber": "calibre", "fire.caliber": "calibre",
"fire.standardPenetration": "penetración estándar", "fire.standardPenetration": "penetración estándar",
"fire.premiumPenetration": "penetración prémium", "fire.premiumPenetration": "penetración prémium",
"fire.tertiaryPenetration": "tertiary penetration",
"fire.damage": "daño", "fire.damage": "daño",
"fire.moduleDamage": "daño al módulo", "fire.moduleDamage": "daño al módulo",
"fire.shellVelocity": "velocidad del proyectil", "fire.shellVelocity": "velocidad del proyectil",
@@ -757,13 +764,51 @@
} }
}, },
"tools": { "tools": {
"guess": {
"name": "Guess the tank",
"button": "Guess away",
"description": "Silhouette mini-game",
"seo_description": "Play a tank guessing game with a silhouette in World of Tanks Blitz",
"search": {
"placeholder": "Type to guess...",
"skip": "Skip",
"guess": "Guess",
"next": "Next",
"no_results": "Sin resultados"
},
"stats": "%s1 / %s2 guessed correctly"
},
"tankopedia": { "tankopedia": {
"search": "Search a stat...",
"name": "Tankopedia", "name": "Tankopedia",
"button": "Encuentra tanques", "button": "Encuentra tanques",
"description": "Enciclopedia de tanques de WOTB", "description": "Enciclopedia de tanques de WOTB",
"seo_description": "Estadísticas, armaduras y más para todos los tanques en World of Tanks Blitz", "seo_description": "Estadísticas, armaduras y más para todos los tanques en World of Tanks Blitz",
"tank_seo_title": "%s1 - Nivel %s2 %s3 %s4 | %s5 Tankopedia | World of Tanks Blitz (WoTB)", "tank_seo_title": "%s1 - Nivel %s2 %s3 %s4 | %s5 Tankopedia | World of Tanks Blitz (WoTB)",
"tank_seo_description": "%s1 blindaje, estadisticas, equipamiento, proviciones y mas.\n%s2 DPM, %3hp alfa, %s4mm penetracion, %s5kph velocidad maxima, %s6 hp salud", "tank_seo_description": "%s1 blindaje, estadisticas, equipamiento, proviciones y mas.\n%s2 DPM, %3hp alfa, %s4mm penetracion, %s5kph velocidad maxima, %s6 hp salud",
"visualizers": {
"rotator": {
"hull": "Hull",
"turret": "Turret",
"hard": "Hard",
"medium": "Medio",
"soft": "Suave",
"effective": "Effective"
},
"ricochet": {
"angle": "Angle",
"normalization": "Normalización",
"effective_angle": "Effective angle",
"armor": "Blindaje",
"no_ricochet": "Explosive shells don't ricochet"
},
"view_range": {
"camo": "Camo",
"percentage": "%s1%",
"ghost_factory": "Ghost Factory",
"dead_rail": "Dead Rail"
}
},
"sandbox": { "sandbox": {
"poses": { "poses": {
"hull_down": "Hull down", "hull_down": "Hull down",
@@ -900,7 +945,7 @@
"characteristics": { "characteristics": {
"title": "Características", "title": "Características",
"compare": { "compare": {
"label": "Comparar", "label": "Comparar con",
"class": "Nivel %s1 - %s2", "class": "Nivel %s1 - %s2",
"tier": "Todos de nivel %s1", "tier": "Todos de nivel %s1",
"all": "Todos los tanques" "all": "Todos los tanques"
+47 -2
View File
@@ -10,7 +10,9 @@
"mm": "%s1mm", "mm": "%s1mm",
"deg": "%s1°", "deg": "%s1°",
"hp": "%s1ps", "hp": "%s1ps",
"x": "x%s1" "x": "x%s1",
"percentage": "%s1%",
"deg_s": "%s1°/s"
}, },
"gun_types": { "gun_types": {
"auto_loader": "Chargement auto", "auto_loader": "Chargement auto",
@@ -651,6 +653,10 @@
} }
}, },
"website": { "website": {
"redirect": {
"title": "301: moved permanently",
"body": "This page has moved. Redirecting..."
},
"settings": { "settings": {
"dev_mode": "Development mode", "dev_mode": "Development mode",
"language": "Language" "language": "Language"
@@ -692,6 +698,7 @@
"fire.caliber": "caliber", "fire.caliber": "caliber",
"fire.standardPenetration": "standard penetration", "fire.standardPenetration": "standard penetration",
"fire.premiumPenetration": "premium penetration", "fire.premiumPenetration": "premium penetration",
"fire.tertiaryPenetration": "tertiary penetration",
"fire.damage": "damage", "fire.damage": "damage",
"fire.moduleDamage": "module damage", "fire.moduleDamage": "module damage",
"fire.shellVelocity": "shell velocity", "fire.shellVelocity": "shell velocity",
@@ -757,13 +764,51 @@
} }
}, },
"tools": { "tools": {
"guess": {
"name": "Guess the tank",
"button": "Guess away",
"description": "Silhouette mini-game",
"seo_description": "Play a tank guessing game with a silhouette in World of Tanks Blitz",
"search": {
"placeholder": "Type to guess...",
"skip": "Skip",
"guess": "Guess",
"next": "Next",
"no_results": "No results"
},
"stats": "%s1 / %s2 guessed correctly"
},
"tankopedia": { "tankopedia": {
"search": "Search a stat...",
"name": "Tankopedia", "name": "Tankopedia",
"button": "Find tanks", "button": "Find tanks",
"description": "Blitz tank encyclopedia", "description": "Blitz tank encyclopedia",
"seo_description": "Statistics, armor, and more for all tanks in World of Tanks Blitz", "seo_description": "Statistics, armor, and more for all tanks in World of Tanks Blitz",
"tank_seo_title": "%s1 - Tier %s2 %s3 %s4 | %s5 Tankopedia | World of Tanks Blitz (WoTB)", "tank_seo_title": "%s1 - Tier %s2 %s3 %s4 | %s5 Tankopedia | World of Tanks Blitz (WoTB)",
"tank_seo_description": "%s1 armor, statistics, equipment, provisions, and more. %s2 DPM, %s3hp alpha, %s4mm penetration, %s5kph top speed, %s6hp health.", "tank_seo_description": "%s1 armor, statistics, equipment, provisions, and more. %s2 DPM, %s3hp alpha, %s4mm penetration, %s5kph top speed, %s6hp health.",
"visualizers": {
"rotator": {
"hull": "Hull",
"turret": "Turret",
"hard": "Hard",
"medium": "Moyen",
"soft": "Soft",
"effective": "Effective"
},
"ricochet": {
"angle": "Angle",
"normalization": "Normalization",
"effective_angle": "Effective angle",
"armor": "Armor",
"no_ricochet": "Explosive shells don't ricochet"
},
"view_range": {
"camo": "Camo",
"percentage": "%s1%",
"ghost_factory": "Ghost Factory",
"dead_rail": "Dead Rail"
}
},
"sandbox": { "sandbox": {
"poses": { "poses": {
"hull_down": "Hull down", "hull_down": "Hull down",
@@ -900,7 +945,7 @@
"characteristics": { "characteristics": {
"title": "Characteristics", "title": "Characteristics",
"compare": { "compare": {
"label": "Compare", "label": "Compare against",
"class": "Tier %s1 %s2", "class": "Tier %s1 %s2",
"tier": "All of tier %s1", "tier": "All of tier %s1",
"all": "All tanks" "all": "All tanks"
+190 -145
View File
@@ -2,7 +2,7 @@
"test": { "test": {
"default": "test", "default": "test",
"long": "This is a long test string. You MUST NEVER see this in the UI. My favorite fruit is %s1 because it has the color of %s2. I like it so much that I will say its name 3 times! %s1! %s1! %s1! Once again, it's %s2, not %s3.", "long": "This is a long test string. You MUST NEVER see this in the UI. My favorite fruit is %s1 because it has the color of %s2. I like it so much that I will say its name 3 times! %s1! %s1! %s1! Once again, it's %s2, not %s3.",
"fox": "The quick brown fox jumps over the lazy dog." "fox": "すばしっこい茶色のキツネが怠け者の犬を飛び越した。"
}, },
"common": { "common": {
"units": { "units": {
@@ -10,7 +10,9 @@
"mm": "%s1mm", "mm": "%s1mm",
"deg": "%s1°", "deg": "%s1°",
"hp": "%s1hp", "hp": "%s1hp",
"x": "x%s1" "x": "x%s1",
"percentage": "%s1%",
"deg_s": "%s1°/s"
}, },
"gun_types": { "gun_types": {
"auto_loader": "自動装填砲", "auto_loader": "自動装填砲",
@@ -33,10 +35,10 @@
"d_1": "昨日" "d_1": "昨日"
}, },
"branches": { "branches": {
"local": "dev", "local": "開発",
"dev": "beta", "dev": "ベータ版",
"opentest": "opentest", "opentest": "オープンテスト",
"preview": "preview" "preview": "プレビュー"
}, },
"locales": { "locales": {
"en": "英語", "en": "英語",
@@ -104,10 +106,10 @@
"3": "駆逐戦車" "3": "駆逐戦車"
}, },
"tank_class_short_plural_lowercase": { "tank_class_short_plural_lowercase": {
"0": "LT", "0": "軽戦車",
"1": "MT", "1": "中戦車",
"2": "HT", "2": "重戦車",
"3": "TD" "3": "駆逐戦車"
}, },
"tank_class_medium": { "tank_class_medium": {
"-1": "不明", "-1": "不明",
@@ -124,9 +126,9 @@
}, },
"regions": { "regions": {
"normal": { "normal": {
"com": "North America", "com": "北米",
"eu": "Europe", "eu": "ヨーロッパ",
"asia": "Asia-Pacific" "asia": "アジア太平洋"
}, },
"short": { "short": {
"com": "NA", "com": "NA",
@@ -142,58 +144,58 @@
"bronze": "ブロンズ" "bronze": "ブロンズ"
}, },
"composite_stats": { "composite_stats": {
"normalized_damage_dealt": "Damage", "normalized_damage_dealt": "ダメージ",
"normalized_damage_received": "Damage received", "normalized_damage_received": "被ダメージ",
"normalized_deaths": "Deathrate", "normalized_deaths": "被撃破率",
"normalized_frags": "Kills", "normalized_frags": "撃破",
"normalized_hits": "Hits", "normalized_hits": "命中",
"normalized_losses": "Lossrate", "normalized_losses": "減衰率",
"normalized_misses": "Misses", "normalized_misses": "非命中数",
"normalized_shots": "Shots", "normalized_shots": "射撃数",
"normalized_spotted": "Spots", "normalized_spotted": "発見数",
"normalized_survived_battles": "Survival rate", "normalized_survived_battles": "生存率",
"normalized_win_and_survived": "Winning and surviving rate", "normalized_win_and_survived": "勝率・生還率",
"normalized_wins": "Winrate", "normalized_wins": "勝率",
"normalized_xp": "XP", "normalized_xp": "経験値",
"normalized_battle_life_time": "Battle time", "normalized_battle_life_time": "戦闘時間",
"cumulative_accuracy": "Accuracy", "cumulative_accuracy": "精度",
"cumulative_battles": "Battles", "cumulative_battles": "戦闘数",
"cumulative_capture_points": "Total capture points", "cumulative_capture_points": "総占領ポイント",
"cumulative_damage_dealt": "Total damage", "cumulative_damage_dealt": "総ダメージ",
"cumulative_damage_ratio": "Damage ratio", "cumulative_damage_ratio": "ダメージ率",
"cumulative_damage_received": "Total damage received", "cumulative_damage_received": "総被ダメージ",
"cumulative_deaths": "Total deaths", "cumulative_deaths": "総被撃破数",
"cumulative_dropped_capture_points": "Total dropped capture points", "cumulative_dropped_capture_points": "総喪失占領ポイント",
"cumulative_frags": "Total kills", "cumulative_frags": "総撃破数",
"cumulative_hits": "Total hits", "cumulative_hits": "総命中数",
"cumulative_inaccuracy": "Inaccuracy", "cumulative_inaccuracy": "非命中率",
"cumulative_kills_to_death_ratio": "Kills to death ratio", "cumulative_kills_to_death_ratio": "撃破/被撃破比",
"cumulative_losses": "Losses", "cumulative_losses": "敗北",
"cumulative_misses": "Total misses", "cumulative_misses": "総非命中数",
"cumulative_shots": "Total shots", "cumulative_shots": "総射撃数",
"cumulative_spotted": "Total spots", "cumulative_spotted": "総発見数",
"cumulative_survived_battles": "Survived battles", "cumulative_survived_battles": "生還した戦闘数",
"cumulative_win_and_survived": "Won and survived battles", "cumulative_win_and_survived": "勝利し生還した戦闘数",
"cumulative_wins": "Wins", "cumulative_wins": "勝利",
"cumulative_xp": "Total XP", "cumulative_xp": "総経験値",
"cumulative_wn8": "WN8", "cumulative_wn8": "WN8",
"cumulative_battle_life_time": "Total battle time" "cumulative_battle_life_time": "総戦闘時間"
} }
}, },
"bot": { "bot": {
"common": { "common": {
"errors": { "errors": {
"clan_not_found": "# Could not find clan\nCouldn't find \"%s1\". Try selecting a clan from the search result.", "clan_not_found": "# クランが見つかりませんでした\n\"%s1\"は見つかりませんでした。検索結果からクランを選択してください。",
"player_not_found": "# Could not find user\nI couldn't find user \"%s1\". Try picking an user from the search result, typing in a valid username, or using the `/link` command.", "player_not_found": "# ユーザーが見つかりませんでした\nユーザー「\"%s1\"」は見つかりませんでした。検索結果からユーザーを選択するか、有効な名前を入力してください。`/link`コマンドを使用することも可能です。",
"player_not_linked": "# Use `/link` to get started\nI don't know who you are but you can tell me today!", "player_not_linked": "# `/link`を使用して始めましょう\nはじめまして!あなたが誰か、私に教えてください。",
"tank_name_not_found": "# Tank not found\nCould not find tank by the name \"%s1\".", "tank_name_not_found": "# 車輌が見つかりませんでした\n\"%s1\"という名前の車輌は見つかりませんでした。",
"tank_id_not_found": "# Tank not found\nCould not find tank by the ID \"%s1\". Try typing the name of the tank instead of a number.", "tank_id_not_found": "# 車輌が見つかりませんでした\n\"%s1\"というIDの車輌は見つかりませんでした。番号ではなく名前で検索してください。",
"no_tank_stats": "# No tank stats available\nThis player doesn't have any stats available. This may not be the player you are looking for.", "no_tank_stats": "# 利用可能な車輌統計がありません\nこのプレイヤーには利用可能な統計がありません。あなたが探しているプレイヤーではない可能性があります。",
"get_help": "Discordサーバーに参加する", "get_help": "Discordサーバーに参加する",
"uncaught_error": "# BlitzKit がエラーに遭遇しました!\n申し訳ありません。お気軽に[Discordの公式サーバー](https://discord.gg/nDt7AjGJQH) をご利用ください。", "uncaught_error": "# BlitzKitがエラーに遭遇しました!\n申し訳ありません。お気軽に[公式Discordサーバー](https://discord.gg/nDt7AjGJQH)にお問い合わせください。",
"preview": "# This command is in preview\n\nYou can only access this command in [the official Discord server](https://discord.gg/nDt7AjGJQH). The command will be generally available soon.", "preview": "このコマンドは現在[公式Discardサーバー](https://discord.gg/nDt7AjGJQH)でのみ利用可能です。間もなく全体で利用可能になります。",
"query_too_small": "# Your search is too short\nYour search must be at least 3 characters long.", "query_too_small": "# 単語が短すぎます\n検索には少なくとも3文字が含まれている必要があります。",
"query_too_long": "# Your search is too long\nYour search must be at most 100 characters long." "query_too_long": "# 単語が長すぎます\n検索は最大で100文字までです。"
}, },
"wn8": { "wn8": {
"name": "WN8", "name": "WN8",
@@ -217,26 +219,26 @@
}, },
"30": { "30": {
"name": "30", "name": "30",
"description": "30 days" "description": "30日"
}, },
"60": { "60": {
"name": "60", "name": "60",
"description": "60 days" "description": "60日"
}, },
"90": { "90": {
"name": "90", "name": "90",
"description": "90日" "description": "90日"
}, },
"career": { "career": {
"name": "総合戦績", "name": "総合戦績",
"description": "Career" "description": "Career"
}, },
"custom": { "custom": {
"name": "custom", "name": "カスタム",
"description": "Custom range", "description": "Custom range",
"options": { "options": {
"start": { "start": {
"name": "start", "name": "開始",
"description": "Start in number of days ago from today" "description": "Start in number of days ago from today"
}, },
"end": { "end": {
@@ -248,21 +250,21 @@
}, },
"options": { "options": {
"clan": { "clan": {
"name": "clan", "name": "クラン",
"description": "The clan name or tag" "description": "クラン名もしくはタグ"
}, },
"tank": { "tank": {
"name": "tank", "name": "車輌",
"description": "The tank to get stats for" "description": "統計を得る車輌"
}, },
"username": { "username": {
"name": "username", "name": "ユーザー名",
"description": "The Blitz username of the player" "description": "プレイヤーのBlitzユーザー名"
}, },
"filters": { "filters": {
"nation": { "nation": {
"name": "nation", "name": "国家",
"description": "Nation" "description": "国家"
}, },
"class": { "class": {
"name": "", "name": "",
@@ -274,8 +276,8 @@
} }
}, },
"region": { "region": {
"name": "region", "name": "地域",
"description": "Region" "description": "地域"
}, },
"tier": { "tier": {
"name": "tier", "name": "tier",
@@ -292,7 +294,7 @@
"custom": "%s1 - %s2 days" "custom": "%s1 - %s2 days"
}, },
"filters": { "filters": {
"none": "No filters", "none": "フィルターなし",
"tier": "Tier %s1" "tier": "Tier %s1"
}, },
"no_data": { "no_data": {
@@ -305,31 +307,31 @@
"refresh": "Refresh" "refresh": "Refresh"
}, },
"hero_stats": { "hero_stats": {
"battles": "Battles", "battles": "戦闘数",
"winrate": "Winrate", "winrate": "勝率",
"damage": "Damage", "damage": "ダメージ",
"damage_ratio": "Damage ratio", "damage_ratio": "ダメージ率",
"tier": "Tier", "tier": "Tier",
"survival": "Survival", "survival": "生存",
"accuracy": "Accuracy", "accuracy": "命中率",
"kills": "Kills" "kills": "撃破"
} }
}, },
"commands": { "commands": {
"auction": { "auction": {
"name": "auction", "name": "オークション",
"description": "Tanks available right now in the auction", "description": "現在オークションで購入可能な車輌",
"body": { "body": {
"title": "Blitz Auction", "title": "Blitzオークション",
"subtitle": "%s1 available • next prices %s2\nBid now: %s3", "subtitle": "%s1 残り• 次の価格 %s2\n今すぐ入札: %s3",
"next": "Next price: %s1", "next": "次の価格: %s1",
"available": "Available: %s1 / %s2" "available": "残り: %s1 / %s2"
}, },
"errors": { "errors": {
"no_auction": "# No ongoing auction\n\nCurrently, there are no tanks available for purchase in the auction. If you think this is an error, please report this discrepancy in [the official Discord Server](https://discord.gg/nDt7AjGJQH)." "no_auction": "# 進行中のオークションはありません\n現在、オークションで購入可能な車輌はありません。もしこれが間違いの場合、[公式Discardサーバー](https://discord.gg/nDt7AjGJQH)に報告してください。"
}, },
"actions": { "actions": {
"bid": "Bid now" "bid": "今すぐ入札"
} }
}, },
"replay": { "replay": {
@@ -337,7 +339,7 @@
"description": "Display replay results" "description": "Display replay results"
}, },
"research": { "research": {
"name": "research", "name": "研究",
"description": "Lists the expenses in researching a line", "description": "Lists the expenses in researching a line",
"options": { "options": {
"target_tank": { "target_tank": {
@@ -369,32 +371,32 @@
}, },
"about": { "about": {
"name": "about", "name": "about",
"description": "All the info you need about the bot", "description": "botについての情報の全て",
"subcommands": { "subcommands": {
"commands": { "commands": {
"name": "commands", "name": "コマンド",
"description": "List of all commands and their descriptions", "description": "全コマンドのリストと説明",
"body": "# Commands\n\nBlitzKit offers the following commands:\n\n" "body": "# コマンド\nBlitzKitは以下のコマンドを提供します:"
}, },
"embeds": { "embeds": {
"name": "embeds", "name": "埋め込み",
"description": "How embeds work" "description": "埋め込みがどう機能するか"
}, },
"introduction": { "introduction": {
"name": "introduction", "name": "introduction",
"description": "About the bot" "description": "botについて"
}, },
"invite": { "invite": {
"name": "invite", "name": "招待",
"description": "How to invite the bot" "description": "botを招待する方法"
}, },
"timezones": { "timezones": {
"name": "timezones", "name": "タイムゾーン",
"description": "How BlitzKit infers and uses your timezone" "description": "How BlitzKit infers and uses your timezone"
}, },
"credits": { "credits": {
"name": "credits", "name": "クレジット",
"description": "People who have helped BlitzKit" "description": "BlitzKitを支援した人々"
} }
} }
}, },
@@ -403,10 +405,10 @@
"description": "A period's breakdown by tanks played", "description": "A period's breakdown by tanks played",
"body": { "body": {
"total": "トータル", "total": "トータル",
"battles": "Battles", "battles": "戦闘数",
"wn8": "WN8", "wn8": "WN8",
"winrate": "Winrate", "winrate": "勝率",
"damage": "Damage", "damage": "ダメージ",
"unknown_tank": "Unknown tank %s1" "unknown_tank": "Unknown tank %s1"
} }
}, },
@@ -432,7 +434,7 @@
"description": "Player statistics" "description": "Player statistics"
}, },
"tank": { "tank": {
"name": "tank", "name": "車輌",
"description": "Tank statistics" "description": "Tank statistics"
} }
} }
@@ -458,21 +460,21 @@
"cards": { "cards": {
"games": { "games": {
"title": "Games", "title": "Games",
"winrate": "Winrate", "winrate": "勝率",
"battles": "Battles", "battles": "戦闘数",
"wins_losses": "Wins / losses" "wins_losses": "Wins / losses"
}, },
"efficiency": { "efficiency": {
"title": "Efficiency", "title": "Efficiency",
"wn8": "WN8", "wn8": "WN8",
"survival": "Survival", "survival": "生存",
"accuracy": "Accuracy" "accuracy": "精度"
}, },
"lethality": { "lethality": {
"title": "Lethality", "title": "Lethality",
"average_damage": "Average damage", "average_damage": "Average damage",
"damage_per_tier": "Damage per tier", "damage_per_tier": "Damage per tier",
"damage_ratio": "Damage ratio", "damage_ratio": "ダメージ比",
"average_kills": "Average kills" "average_kills": "Average kills"
}, },
"miscellaneous": { "miscellaneous": {
@@ -480,7 +482,7 @@
"average_tier": "Average tier", "average_tier": "Average tier",
"average_spots": "Average spots", "average_spots": "Average spots",
"average_xp": "Average XP", "average_xp": "Average XP",
"kills_to_death_ratio": "Kills to death ratio" "kills_to_death_ratio": "撃破/被撃破比"
} }
} }
} }
@@ -568,7 +570,7 @@
} }
}, },
"today": { "today": {
"name": "today", "name": "今日",
"description": "Today's played tanks and statistics" "description": "Today's played tanks and statistics"
}, },
"stats": { "stats": {
@@ -617,8 +619,8 @@
"body": { "body": {
"title": "%s1's information", "title": "%s1's information",
"nickname": "Nickname", "nickname": "Nickname",
"battles": "Battles", "battles": "戦闘数",
"winrate": "Winrate", "winrate": "勝率",
"account_id": "Account ID", "account_id": "Account ID",
"created": "Created", "created": "Created",
"last_battle": "Last battle" "last_battle": "Last battle"
@@ -629,7 +631,7 @@
"description": "Rating player's statistics", "description": "Rating player's statistics",
"subcommands": { "subcommands": {
"today": { "today": {
"name": "today", "name": "今日",
"description": "Today's rating statistics" "description": "Today's rating statistics"
}, },
"season": { "season": {
@@ -651,6 +653,10 @@
} }
}, },
"website": { "website": {
"redirect": {
"title": "301: moved permanently",
"body": "This page has moved. Redirecting..."
},
"settings": { "settings": {
"dev_mode": "開発者モード", "dev_mode": "開発者モード",
"language": "言語 / Language" "language": "言語 / Language"
@@ -670,11 +676,11 @@
"recent": "最近の閲覧", "recent": "最近の閲覧",
"select_all": "全て選択", "select_all": "全て選択",
"count_singular": "1 輌", "count_singular": "1 輌",
"count_plural": "%s1 輌", "count_plural": "%s1輌",
"sorting_by": "並べ替え:%s1", "sorting_by": ":%s1で並び替え",
"no_tanks_found": { "no_tanks_found": {
"body": "該当する車輌が存在しません。", "body": "該当する車輌が存在しません。",
"search_again": "もう一度探してください。", "search_again": "もう一度検索してください。",
"clear_filters": "フィルターをクリアしてください" "clear_filters": "フィルターをクリアしてください"
}, },
"sort": { "sort": {
@@ -687,21 +693,22 @@
"survivability.volume": "体積", "survivability.volume": "体積",
"survivability.length": "全長", "survivability.length": "全長",
"fire.dpm": "通常弾DPM", "fire.dpm": "通常弾DPM",
"fire.dpmPremium": "課金弾DPM", "fire.dpmPremium": "プレミアム弾DPM",
"fire.reload": "装填時間", "fire.reload": "装填時間",
"fire.caliber": "砲口径", "fire.caliber": "砲口径",
"fire.standardPenetration": "通常弾貫通力", "fire.standardPenetration": "通常弾貫通力",
"fire.premiumPenetration": "課金弾貫通力", "fire.premiumPenetration": "課金弾貫通力",
"fire.tertiaryPenetration": "tertiary penetration",
"fire.damage": "ダメージ", "fire.damage": "ダメージ",
"fire.moduleDamage": "モジュールダメージ", "fire.moduleDamage": "モジュールダメージ",
"fire.shellVelocity": "弾速", "fire.shellVelocity": "弾速",
"fire.shellRange": "射程範囲", "fire.shellRange": "射程範囲",
"fire.shellCapacity": "総弾数", "fire.shellCapacity": "総弾数",
"fire.aimTime": "照準時間", "fire.aimTime": "照準時間",
"fire.dispersionStill": "静止時散布界", "fire.dispersionStill": "静止時拡散",
"fire.dispersionMoving": "移動時散布界", "fire.dispersionMoving": "移動時拡散",
"fire.gunDepression": "主砲俯角", "fire.gunDepression": "俯角",
"fire.gunElevation": "主砲仰角", "fire.gunElevation": "仰角",
"maneuverability.forwardsSpeed": "前進速度", "maneuverability.forwardsSpeed": "前進速度",
"maneuverability.backwardsSpeed": "後退速度", "maneuverability.backwardsSpeed": "後退速度",
"maneuverability.power": "馬力", "maneuverability.power": "馬力",
@@ -710,17 +717,17 @@
"maneuverability.traverseSpeed": "車体旋回速度" "maneuverability.traverseSpeed": "車体旋回速度"
}, },
"sort_dropdown": { "sort_dropdown": {
"label": "ソート", "label": "並び替え",
"groups": { "groups": {
"sort": { "sort": {
"no_sort": "ソートなし", "no_sort": "並び替えなし",
"label": "並べ替え項目", "label": "並べ替え項目",
"fire": "火力", "fire": "火力",
"maneuverability": "機動性", "maneuverability": "機動性",
"survivability": "生存性" "survivability": "生存性"
}, },
"direction": { "direction": {
"label": "方法", "label": "方向",
"ascending": "昇順", "ascending": "昇順",
"descending": "降順" "descending": "降順"
} }
@@ -742,13 +749,13 @@
}, },
"hot_tanks": { "hot_tanks": {
"title": "人気の車輌", "title": "人気の車輌",
"subtitle": "過去 %s1 日間" "subtitle": "過去 %s1日間"
}, },
"other_projects": { "other_projects": {
"title": "Other cool projects" "title": "他のプロジェクト"
}, },
"help_translate": "%s1の %s2への翻訳にご協力ください!", "help_translate": "%s1の %s2への翻訳にご協力ください!",
"seo_description": "Tools for everything World of Tanks Blitz" "seo_description": "World of Tanks Blitz全般のツール"
}, },
"docs": { "docs": {
"patches": { "patches": {
@@ -757,13 +764,51 @@
} }
}, },
"tools": { "tools": {
"guess": {
"name": "Guess the tank",
"button": "Guess away",
"description": "Silhouette mini-game",
"seo_description": "Play a tank guessing game with a silhouette in World of Tanks Blitz",
"search": {
"placeholder": "Type to guess...",
"skip": "Skip",
"guess": "Guess",
"next": "Next",
"no_results": "該当なし"
},
"stats": "%s1 / %s2 guessed correctly"
},
"tankopedia": { "tankopedia": {
"search": "Search a stat...",
"name": "Tankopedia", "name": "Tankopedia",
"button": "戦車を探す", "button": "戦車を探す",
"description": "Blitz戦車百科", "description": "Blitz戦車百科",
"seo_description": "Statistics, armor, and more for all tanks in World of Tanks Blitz", "seo_description": "Statistics, armor, and more for all tanks in World of Tanks Blitz",
"tank_seo_title": "%s1 - Tier %s2 %s3 %s4 | %s5 Tankopedia | World of Tanks Blitz (WoTB)", "tank_seo_title": "%s1 - Tier %s2 %s3 %s4 | %s5 Tankopedia | World of Tanks Blitz (WoTB)",
"tank_seo_description": "%s1 armor, statistics, equipment, provisions, and more. %s2 DPM, %s3hp alpha, %s4mm penetration, %s5kph top speed, %s6hp health.", "tank_seo_description": "%s1 armor, statistics, equipment, provisions, and more. %s2 DPM, %s3hp alpha, %s4mm penetration, %s5kph top speed, %s6hp health.",
"visualizers": {
"rotator": {
"hull": "Hull",
"turret": "Turret",
"hard": "Hard",
"medium": "不整地",
"soft": "軟弱地",
"effective": "Effective"
},
"ricochet": {
"angle": "Angle",
"normalization": "標準化",
"effective_angle": "Effective angle",
"armor": "装甲",
"no_ricochet": "Explosive shells don't ricochet"
},
"view_range": {
"camo": "Camo",
"percentage": "%s1%",
"ghost_factory": "Ghost Factory",
"dead_rail": "Dead Rail"
}
},
"sandbox": { "sandbox": {
"poses": { "poses": {
"hull_down": "ハルダウン", "hull_down": "ハルダウン",
@@ -795,7 +840,7 @@
"normalization": "標準化", "normalization": "標準化",
"ricochet": "跳弾角度", "ricochet": "跳弾角度",
"explosion_radius": "爆風半径", "explosion_radius": "爆風半径",
"exit": "決定", "exit": "終了",
"reset": "リセット" "reset": "リセット"
}, },
"advanced": "高度なハイライト", "advanced": "高度なハイライト",
@@ -900,7 +945,7 @@
"characteristics": { "characteristics": {
"title": "性能値", "title": "性能値",
"compare": { "compare": {
"label": "性能比較", "label": "比較対象",
"class": "Tier %s1 %s2", "class": "Tier %s1 %s2",
"tier": "Tier %s1 全車輌", "tier": "Tier %s1 全車輌",
"all": "全車輌" "all": "全車輌"
@@ -952,22 +997,22 @@
"azimuthRight": "右射界", "azimuthRight": "右射界",
"speedForwards": "前進", "speedForwards": "前進",
"speedBackwards": "後退", "speedBackwards": "後退",
"hardTerrainCoefficient": "道", "hardTerrainCoefficient": "舗装路での地形走破能力",
"hardTerrainCoefficientRaw": "道", "hardTerrainCoefficientRaw": "舗装路での地形係数",
"mediumTerrainCoefficient": "地面", "mediumTerrainCoefficient": "不整地",
"mediumTerrainCoefficientRaw": "地面", "mediumTerrainCoefficientRaw": "不整地",
"softTerrainCoefficient": "水辺", "softTerrainCoefficient": "軟弱地",
"softTerrainCoefficientRaw": "水辺", "softTerrainCoefficientRaw": "軟弱地",
"enginePower": "エンジン出力", "enginePower": "エンジン出力",
"powerToWeightRatioHardTerrain": "道", "powerToWeightRatioHardTerrain": "舗装路での重量毎出力値",
"powerToWeightRatioMediumTerrain": "地面", "powerToWeightRatioMediumTerrain": "不整地",
"powerToWeightRatioSoftTerrain": "水辺", "powerToWeightRatioSoftTerrain": "軟弱地",
"weight": "重量", "weight": "重量",
"turretTraverseSpeed": "砲塔旋回速度", "turretTraverseSpeed": "砲塔旋回速度",
"gunTraverseSpeed": "主砲旋回速度", "gunTraverseSpeed": "主砲旋回速度",
"hullTraverseHardTerrain": "道", "hullTraverseHardTerrain": "舗装路での旋回速度",
"hullTraverseMediumTerrain": "地面", "hullTraverseMediumTerrain": "不整地",
"hullTraverseSoftTerrain": "水辺", "hullTraverseSoftTerrain": "軟弱地",
"health": "耐久値", "health": "耐久値",
"fireChance": "火災発生率", "fireChance": "火災発生率",
"viewRange": "視認範囲", "viewRange": "視認範囲",
@@ -980,7 +1025,7 @@
"height": "全高", "height": "全高",
"length": "車体長", "length": "車体長",
"volume": "体積", "volume": "体積",
"shellRange": "射程範囲", "shellRange": "射程",
"shellCapacity": "総弾数", "shellCapacity": "総弾数",
"gunType": "主砲タイプ", "gunType": "主砲タイプ",
"penetrationAt250m": "250m での貫通力" "penetrationAt250m": "250m での貫通力"
+48 -3
View File
@@ -10,7 +10,9 @@
"mm": "%s1mm", "mm": "%s1mm",
"deg": "%s1°", "deg": "%s1°",
"hp": "%s1hp", "hp": "%s1hp",
"x": "x%s1" "x": "x%s1",
"percentage": "%s1%",
"deg_s": "%s1°/s"
}, },
"gun_types": { "gun_types": {
"auto_loader": "Auto loader", "auto_loader": "Auto loader",
@@ -378,7 +380,7 @@
}, },
"embeds": { "embeds": {
"name": "osadzenie", "name": "osadzenie",
"description": "Jak działa osadzanie" "description": "Jak działają osadzone"
}, },
"introduction": { "introduction": {
"name": "wprowadzenie", "name": "wprowadzenie",
@@ -651,6 +653,10 @@
} }
}, },
"website": { "website": {
"redirect": {
"title": "301: moved permanently",
"body": "This page has moved. Redirecting..."
},
"settings": { "settings": {
"dev_mode": "Development mode", "dev_mode": "Development mode",
"language": "Language" "language": "Language"
@@ -692,6 +698,7 @@
"fire.caliber": "caliber", "fire.caliber": "caliber",
"fire.standardPenetration": "standard penetration", "fire.standardPenetration": "standard penetration",
"fire.premiumPenetration": "premium penetration", "fire.premiumPenetration": "premium penetration",
"fire.tertiaryPenetration": "tertiary penetration",
"fire.damage": "damage", "fire.damage": "damage",
"fire.moduleDamage": "module damage", "fire.moduleDamage": "module damage",
"fire.shellVelocity": "shell velocity", "fire.shellVelocity": "shell velocity",
@@ -757,13 +764,51 @@
} }
}, },
"tools": { "tools": {
"guess": {
"name": "Guess the tank",
"button": "Guess away",
"description": "Silhouette mini-game",
"seo_description": "Play a tank guessing game with a silhouette in World of Tanks Blitz",
"search": {
"placeholder": "Type to guess...",
"skip": "Skip",
"guess": "Guess",
"next": "Next",
"no_results": "Brak wyników"
},
"stats": ""
},
"tankopedia": { "tankopedia": {
"search": "Search a stat...",
"name": "Tankopedia", "name": "Tankopedia",
"button": "Find tanks", "button": "Find tanks",
"description": "Blitz tank encyclopedia", "description": "Blitz tank encyclopedia",
"seo_description": "Statistics, armor, and more for all tanks in World of Tanks Blitz", "seo_description": "Statistics, armor, and more for all tanks in World of Tanks Blitz",
"tank_seo_title": "%s1 - Tier %s2 %s3 %s4 | %s5 Tankopedia | World of Tanks Blitz (WoTB)", "tank_seo_title": "%s1 - Tier %s2 %s3 %s4 | %s5 Tankopedia | World of Tanks Blitz (WoTB)",
"tank_seo_description": "%s1 armor, statistics, equipment, provisions, and more. %s2 DPM, %s3hp alpha, %s4mm penetration, %s5kph top speed, %s6hp health.", "tank_seo_description": "%s1 armor, statistics, equipment, provisions, and more. %s2 DPM, %s3hp alpha, %s4mm penetration, %s5kph top speed, %s6hp health.",
"visualizers": {
"rotator": {
"hull": "Hull",
"turret": "Turret",
"hard": "Hard",
"medium": "Medium",
"soft": "Soft",
"effective": "Effective"
},
"ricochet": {
"angle": "Angle",
"normalization": "Normalization",
"effective_angle": "Effective angle",
"armor": "Armor",
"no_ricochet": "Explosive shells don't ricochet"
},
"view_range": {
"camo": "Camo",
"percentage": "%s1%",
"ghost_factory": "Ghost Factory",
"dead_rail": "Dead Rail"
}
},
"sandbox": { "sandbox": {
"poses": { "poses": {
"hull_down": "Hull down", "hull_down": "Hull down",
@@ -900,7 +945,7 @@
"characteristics": { "characteristics": {
"title": "Characteristics", "title": "Characteristics",
"compare": { "compare": {
"label": "Compare", "label": "Compare against",
"class": "Tier %s1 %s2", "class": "Tier %s1 %s2",
"tier": "All of tier %s1", "tier": "All of tier %s1",
"all": "All tanks" "all": "All tanks"
+47 -2
View File
@@ -10,7 +10,9 @@
"mm": "%s1mm", "mm": "%s1mm",
"deg": "%s1°", "deg": "%s1°",
"hp": "%s1hp", "hp": "%s1hp",
"x": "x%s1" "x": "x%s1",
"percentage": "%s1%",
"deg_s": "%s1°/s"
}, },
"gun_types": { "gun_types": {
"auto_loader": "Autocarregador", "auto_loader": "Autocarregador",
@@ -651,6 +653,10 @@
} }
}, },
"website": { "website": {
"redirect": {
"title": "301: moved permanently",
"body": "This page has moved. Redirecting..."
},
"settings": { "settings": {
"dev_mode": "Modo de desenvolvimento", "dev_mode": "Modo de desenvolvimento",
"language": "Idioma" "language": "Idioma"
@@ -692,6 +698,7 @@
"fire.caliber": "calibre", "fire.caliber": "calibre",
"fire.standardPenetration": "penetração padrão", "fire.standardPenetration": "penetração padrão",
"fire.premiumPenetration": "penetração premium", "fire.premiumPenetration": "penetração premium",
"fire.tertiaryPenetration": "tertiary penetration",
"fire.damage": "dano", "fire.damage": "dano",
"fire.moduleDamage": "dano a módulos", "fire.moduleDamage": "dano a módulos",
"fire.shellVelocity": "velocidade do projétil", "fire.shellVelocity": "velocidade do projétil",
@@ -757,13 +764,51 @@
} }
}, },
"tools": { "tools": {
"guess": {
"name": "Guess the tank",
"button": "Guess away",
"description": "Silhouette mini-game",
"seo_description": "Play a tank guessing game with a silhouette in World of Tanks Blitz",
"search": {
"placeholder": "Type to guess...",
"skip": "Skip",
"guess": "Guess",
"next": "Next",
"no_results": "Sem resultados"
},
"stats": "%s1 / %s2 guessed correctly"
},
"tankopedia": { "tankopedia": {
"search": "Search a stat...",
"name": "Tanquepedia", "name": "Tanquepedia",
"button": "Encontrar tanques", "button": "Encontrar tanques",
"description": "Blitz enciclopédia de tanques", "description": "Blitz enciclopédia de tanques",
"seo_description": "Estatísticas, blindagem, e mais para todos os tanques de Wolrd of Tanks Blitz", "seo_description": "Estatísticas, blindagem, e mais para todos os tanques de Wolrd of Tanks Blitz",
"tank_seo_title": "%s1 - Nível %s2 %s3 %s4 | %s5 Tanquepedia | World of Tanks Blitz (WoTB)", "tank_seo_title": "%s1 - Nível %s2 %s3 %s4 | %s5 Tanquepedia | World of Tanks Blitz (WoTB)",
"tank_seo_description": "%s1 blindagem, estatísticas, equipamentos, provisões e mais. %s2 DPM, %s3hp alfa, %s4mm de penetração, %s5km/h velocidade máxima, %s6hp vida.", "tank_seo_description": "%s1 blindagem, estatísticas, equipamentos, provisões e mais. %s2 DPM, %s3hp alfa, %s4mm de penetração, %s5km/h velocidade máxima, %s6hp vida.",
"visualizers": {
"rotator": {
"hull": "Hull",
"turret": "Turret",
"hard": "Hard",
"medium": "Médio",
"soft": "Macio",
"effective": "Effective"
},
"ricochet": {
"angle": "Angle",
"normalization": "Normalização",
"effective_angle": "Effective angle",
"armor": "Blindagem",
"no_ricochet": "Explosive shells don't ricochet"
},
"view_range": {
"camo": "Camo",
"percentage": "%s1%",
"ghost_factory": "Ghost Factory",
"dead_rail": "Dead Rail"
}
},
"sandbox": { "sandbox": {
"poses": { "poses": {
"hull_down": "Casco para baixo", "hull_down": "Casco para baixo",
@@ -900,7 +945,7 @@
"characteristics": { "characteristics": {
"title": "Características", "title": "Características",
"compare": { "compare": {
"label": "Comparar", "label": "Comparar com",
"class": "Nível %s1 %s2", "class": "Nível %s1 %s2",
"tier": "Tudo de nível %s1", "tier": "Tudo de nível %s1",
"all": "Todos os tanques" "all": "Todos os tanques"
+49 -4
View File
@@ -10,7 +10,9 @@
"mm": "%s1мм", "mm": "%s1мм",
"deg": "%s1°", "deg": "%s1°",
"hp": "%s1hp", "hp": "%s1hp",
"x": "x%s1" "x": "x%s1",
"percentage": "%s1%",
"deg_s": "%s1°/с"
}, },
"gun_types": { "gun_types": {
"auto_loader": "Барабан", "auto_loader": "Барабан",
@@ -651,6 +653,10 @@
} }
}, },
"website": { "website": {
"redirect": {
"title": "301: перемещено навсегда",
"body": "Эта страница перемещена. Перенаправление..."
},
"settings": { "settings": {
"dev_mode": "Режим разработчика", "dev_mode": "Режим разработчика",
"language": "Язык" "language": "Язык"
@@ -691,7 +697,8 @@
"fire.reload": "перезарядка", "fire.reload": "перезарядка",
"fire.caliber": "калибр", "fire.caliber": "калибр",
"fire.standardPenetration": "базовое пробитие", "fire.standardPenetration": "базовое пробитие",
"fire.premiumPenetration": "улучшенное пробитие ", "fire.premiumPenetration": "премиумное пробитие ",
"fire.tertiaryPenetration": "пробитие третьего снаряда",
"fire.damage": "урон", "fire.damage": "урон",
"fire.moduleDamage": "урон по модулям", "fire.moduleDamage": "урон по модулям",
"fire.shellVelocity": "скорость снаряда", "fire.shellVelocity": "скорость снаряда",
@@ -757,13 +764,51 @@
} }
}, },
"tools": { "tools": {
"guess": {
"name": "Угадайте танк",
"button": "Угадать",
"description": "Мини-игра «Силуэт»",
"seo_description": "Играйте угадывая силуэт танка из World of Tanks Blitz",
"search": {
"placeholder": "Введите догадку...",
"skip": "Пропустить",
"guess": "Угадать",
"next": "Следующий",
"no_results": "Ничего не найденo"
},
"stats": "%s1 / %s2 угадано верно"
},
"tankopedia": { "tankopedia": {
"search": "Поиск характеристик...",
"name": "Танкопедия", "name": "Танкопедия",
"button": "Поиск танков", "button": "Поиск танков",
"description": "Танковая энциклопедия Blitz", "description": "Танковая энциклопедия Blitz",
"seo_description": "Статистика, броня и многое другое по всем танкам World of Tanks Blitz", "seo_description": "Статистика, броня и многое другое по всем танкам World of Tanks Blitz",
"tank_seo_title": "%s1 - %s4 %s3 %s2 уровня | Танкопедия %s5 | World of Tanks Blitz (WoTB)", "tank_seo_title": "%s1 - %s4 %s3 %s2 уровня | Танкопедия %s5 | World of Tanks Blitz (WoTB)",
"tank_seo_description": "%s1 броня, статистика, оборудование, снабжение и многое другое. %s2 УВМ, %s3hp альфа, %s4mm пробитие, %s5км/ч лучшая скорость, %s6hp здоровье.", "tank_seo_description": "%s1 броня, статистика, оборудование, снабжение и многое другое. %s2 УВМ, %s3hp альфа, %s4mm пробитие, %s5км/ч лучшая скорость, %s6hp здоровье.",
"visualizers": {
"rotator": {
"hull": "Корпус",
"turret": "Башня",
"hard": "Твёрдые",
"medium": "Средние",
"soft": "Мягкие",
"effective": "Эффективно"
},
"ricochet": {
"angle": "Угол",
"normalization": "Нормализация",
"effective_angle": "Эффективный угол",
"armor": "Броня",
"no_ricochet": "Разрывные снаряды не рикошетят"
},
"view_range": {
"camo": "Камо",
"percentage": "%s1%",
"ghost_factory": "Промзона",
"dead_rail": "Эшелон"
}
},
"sandbox": { "sandbox": {
"poses": { "poses": {
"hull_down": "За холмом", "hull_down": "За холмом",
@@ -900,7 +945,7 @@
"characteristics": { "characteristics": {
"title": "Характеристики", "title": "Характеристики",
"compare": { "compare": {
"label": "Сравнение", "label": "Сравнивать с",
"class": "%s2 %s1 уровня", "class": "%s2 %s1 уровня",
"tier": "Все %s1 уровня", "tier": "Все %s1 уровня",
"all": "Все танки" "all": "Все танки"
@@ -1143,7 +1188,7 @@
"description": "Встраиваемые элементы для стримов", "description": "Встраиваемые элементы для стримов",
"seo_description": "Создать вставки для стримов по World of Tanks Blitz с невероятной кастомизации", "seo_description": "Создать вставки для стримов по World of Tanks Blitz с невероятной кастомизации",
"coming_soon": "Скоро появятся новые встраиваемые элементы.", "coming_soon": "Скоро появятся новые встраиваемые элементы.",
"suggest": "Предложить идеи", "suggest": "Предложить идеи.",
"preview": { "preview": {
"title": "Предпросмотр", "title": "Предпросмотр",
"upload": "Загрузить фон для теста" "upload": "Загрузить фон для теста"
+53 -8
View File
@@ -2,7 +2,7 @@
"test": { "test": {
"default": "тест", "default": "тест",
"long": "This is a long test string. You MUST NEVER see this in the UI. My favorite fruit is %s1 because it has the color of %s2. I like it so much that I will say its name 3 times! %s1! %s1! %s1! Once again, it's %s2, not %s3.", "long": "This is a long test string. You MUST NEVER see this in the UI. My favorite fruit is %s1 because it has the color of %s2. I like it so much that I will say its name 3 times! %s1! %s1! %s1! Once again, it's %s2, not %s3.",
"fox": "The quick brown fox jumps over the lazy dog." "fox": "Швидка бура лисиця перестрибує через лінивого собаку."
}, },
"common": { "common": {
"units": { "units": {
@@ -10,7 +10,9 @@
"mm": "%s1мм", "mm": "%s1мм",
"deg": "%s1°", "deg": "%s1°",
"hp": "%s1хп", "hp": "%s1хп",
"x": "х%s1" "x": "х%s1",
"percentage": "%s1%",
"deg_s": "%s1°/с"
}, },
"gun_types": { "gun_types": {
"auto_loader": "Магазинна система заряджання", "auto_loader": "Магазинна система заряджання",
@@ -411,10 +413,10 @@
} }
}, },
"debug": { "debug": {
"name": "debug", "name": "налагодження",
"description": "Debug information about the bot", "description": "Інформація про налагодження бота",
"body": { "body": {
"title": "# Debug\n\n", "title": "# Налагодження\n\n",
"version": "Версія", "version": "Версія",
"shard": { "shard": {
"label": "Уламок", "label": "Уламок",
@@ -497,7 +499,7 @@
}, },
"embed": { "embed": {
"title": "Невірний обліковий запис?", "title": "Невірний обліковий запис?",
"description": "Use the command again and select a username from the search results." "description": "Використайте команду ще раз і виберіть ім'я користувача з результатів пошуку."
} }
}, },
"search_clans": { "search_clans": {
@@ -506,7 +508,7 @@
"options": { "options": {
"limit": { "limit": {
"name": "ліміт", "name": "ліміт",
"description": "The max number of clan results (default: %s1)" "description": "Максимальна кількість результатів клану (за замовчуванням: %s1)"
} }
}, },
"body": { "body": {
@@ -651,6 +653,10 @@
} }
}, },
"website": { "website": {
"redirect": {
"title": "301: moved permanently",
"body": "This page has moved. Redirecting..."
},
"settings": { "settings": {
"dev_mode": "Development mode", "dev_mode": "Development mode",
"language": "Мова" "language": "Мова"
@@ -692,6 +698,7 @@
"fire.caliber": "калібр", "fire.caliber": "калібр",
"fire.standardPenetration": "базове пробиття", "fire.standardPenetration": "базове пробиття",
"fire.premiumPenetration": "преміум пробиття", "fire.premiumPenetration": "преміум пробиття",
"fire.tertiaryPenetration": "tertiary penetration",
"fire.damage": "шкода", "fire.damage": "шкода",
"fire.moduleDamage": "шкода по модулях", "fire.moduleDamage": "шкода по модулях",
"fire.shellVelocity": "швидкість польоту снаряда", "fire.shellVelocity": "швидкість польоту снаряда",
@@ -757,13 +764,51 @@
} }
}, },
"tools": { "tools": {
"guess": {
"name": "Guess the tank",
"button": "Guess away",
"description": "Silhouette mini-game",
"seo_description": "Play a tank guessing game with a silhouette in World of Tanks Blitz",
"search": {
"placeholder": "Type to guess...",
"skip": "Skip",
"guess": "Guess",
"next": "Next",
"no_results": "Немає результатів"
},
"stats": "%s1 / %s2 guessed correctly"
},
"tankopedia": { "tankopedia": {
"search": "Search a stat...",
"name": "Танкопедія", "name": "Танкопедія",
"button": "Знайти танки", "button": "Знайти танки",
"description": "Танкова енциклопедія", "description": "Танкова енциклопедія",
"seo_description": "Характеристики, броня та інше для всіх танків WoT Blitz", "seo_description": "Характеристики, броня та інше для всіх танків WoT Blitz",
"tank_seo_title": "%s1 - Рівень %s2 %s3 %s4 | %s5 Танкопедія | WoT Blitz", "tank_seo_title": "%s1 - Рівень %s2 %s3 %s4 | %s5 Танкопедія | WoT Blitz",
"tank_seo_description": "%s1 броня, характеристики, обладнання, амуніція та більше. %s2 шкода на хвилину, %s3 разова шкода, %s4 мм пробиття, %s5 км/год максимальна швидкість, %s6 міцність.", "tank_seo_description": "%s1 броня, характеристики, обладнання, амуніція та більше. %s2 шкода на хвилину, %s3 разова шкода, %s4 мм пробиття, %s5 км/год максимальна швидкість, %s6 міцність.",
"visualizers": {
"rotator": {
"hull": "Hull",
"turret": "Turret",
"hard": "Hard",
"medium": "Середній",
"soft": "Soft",
"effective": "Effective"
},
"ricochet": {
"angle": "Angle",
"normalization": "Нормалізація",
"effective_angle": "Effective angle",
"armor": "Броня",
"no_ricochet": "Explosive shells don't ricochet"
},
"view_range": {
"camo": "Camo",
"percentage": "%s1%",
"ghost_factory": "Ghost Factory",
"dead_rail": "Dead Rail"
}
},
"sandbox": { "sandbox": {
"poses": { "poses": {
"hull_down": "Від башти", "hull_down": "Від башти",
@@ -900,7 +945,7 @@
"characteristics": { "characteristics": {
"title": "Characteristics", "title": "Characteristics",
"compare": { "compare": {
"label": "Порівняти", "label": "Compare against",
"class": "Tier %s1 %s2", "class": "Tier %s1 %s2",
"tier": "All of tier %s1", "tier": "All of tier %s1",
"all": "Усі танки" "all": "Усі танки"
File diff suppressed because it is too large. Load diff
+1 -1
View File
@@ -3,7 +3,7 @@ import { mkdir, writeFile } from 'fs/promises';
import { parse as parsePath } from 'path'; import { parse as parsePath } from 'path';
import ProgressBar from 'progress'; import ProgressBar from 'progress';
import { parse as parseYaml, stringify as stringifyYaml } from 'yaml'; import { parse as parseYaml, stringify as stringifyYaml } from 'yaml';
import { dvp } from '../../../submodules/blitzkit-closed/src/dvp'; import { dvp } from '../../../submodules/blitzkit-closed/src/dava/dvp';
import { readStringDVPL } from '../src/core/blitz/readStringDVPL'; import { readStringDVPL } from '../src/core/blitz/readStringDVPL';
import { DATA } from './buildAssets/constants'; import { DATA } from './buildAssets/constants';
import { readYAMLDVPL } from './core/blitz/readYAMLDVPL'; import { readYAMLDVPL } from './core/blitz/readYAMLDVPL';
+2 -3
View File
@@ -8,7 +8,6 @@ import {
Samples, Samples,
averageDefinitionsAllStatsKeys, averageDefinitionsAllStatsKeys,
emptySamples, emptySamples,
encodePBBuffer,
getAccountInfo, getAccountInfo,
getTankStats, getTankStats,
idToRegion, idToRegion,
@@ -235,11 +234,11 @@ async function postWork() {
commitAssets('averages', [ commitAssets('averages', [
{ {
path: `averages/${latest}.pb`, path: `averages/${latest}.pb`,
content: encodePBBuffer(AverageDefinitions, averageDefinitions), content: AverageDefinitions.encode(averageDefinitions).finish(),
}, },
{ {
path: 'averages/manifest.json', path: 'averages/manifest.json',
content: Buffer.from(JSON.stringify(manifest), 'utf-8'), content: new TextEncoder().encode(JSON.stringify(manifest)),
}, },
]); ]);
} }
@@ -7,7 +7,6 @@ import { FileChange } from '../core/github/commitMultipleFiles';
export async function blitzkitTankIcons() { export async function blitzkitTankIcons() {
console.log('Building blitzkit tank icons...'); console.log('Building blitzkit tank icons...');
console.log('Starting website dev server...');
const browser = await launch(); const browser = await launch();
const page = await browser.newPage(); const page = await browser.newPage();
const tanks = Object.values((await fetchTankDefinitions()).tanks); const tanks = Object.values((await fetchTankDefinitions()).tanks);
@@ -19,12 +18,14 @@ export async function blitzkitTankIcons() {
width: BLITZKIT_TANK_ICON_SIZE.width - 1, width: BLITZKIT_TANK_ICON_SIZE.width - 1,
height: BLITZKIT_TANK_ICON_SIZE.height, height: BLITZKIT_TANK_ICON_SIZE.height,
}); });
await page.goto(`http://localhost:4321/api/tankopedia/tank-icon/${id}/`, {
waitUntil: 'networkidle0',
});
if (index === 0) { try {
console.log('Dev server started!'); await page.goto(`http://localhost:4321/api/tankopedia/tank-icon/${id}/`, {
waitUntil: 'networkidle0',
});
} catch (error) {
console.error(`${id} ${name} time out`, error);
continue;
} }
const screenshot = await page.screenshot({ const screenshot = await page.screenshot({
@@ -5,11 +5,15 @@ const WINDOWS_APPS = 'C:/Program Files/WindowsApps';
const wotbPackageRegex = /7458BE2C\..+_\d+(\.\d+)+_x64__.+/; const wotbPackageRegex = /7458BE2C\..+_\d+(\.\d+)+_x64__.+/;
const isDepot = argv.includes('--depot'); const isDepot = argv.includes('--depot');
const isManual = argv.includes('--manual');
let data: string; let data: string;
let compressed: boolean; let compressed: boolean;
if (isDepot) { if (isManual) {
data = '../../temp/game/Data';
compressed = true;
} else if (isDepot) {
const [installationVersion] = await readdir(`../../depots/444202`); const [installationVersion] = await readdir(`../../depots/444202`);
data = `../../depots/444202/${installationVersion}/Data`; data = `../../depots/444202/${installationVersion}/Data`;
compressed = true; compressed = true;
File diff suppressed because it is too large. Load diff
+6 -6
View File
@@ -1,4 +1,4 @@
import { Avatar, encodePBBuffer, fetchGlossary, Gallery } from '@blitzkit/core'; import { Avatar, fetchGlossary, Gallery } from '@blitzkit/core';
import locales from '@blitzkit/i18n/locales.json'; import locales from '@blitzkit/i18n/locales.json';
import { extname } from 'path'; import { extname } from 'path';
import ProgressBar from 'progress'; import ProgressBar from 'progress';
@@ -68,13 +68,13 @@ export async function glossary() {
gallery.avatars.push(avatar); gallery.avatars.push(avatar);
const content = await fetch(url).then((response) => const content = await fetch(url)
response.arrayBuffer(), .then((response) => response.arrayBuffer())
); .then((buffer) => new Uint8Array(buffer));
changes.push({ changes.push({
path: `gallery/avatars/${key}${avatar.extension}`, path: `gallery/avatars/${key}${avatar.extension}`,
content: Buffer.from(content), content,
}); });
bar.tick(); bar.tick();
@@ -83,7 +83,7 @@ export async function glossary() {
changes.push({ changes.push({
path: 'definitions/gallery.pb', path: 'definitions/gallery.pb',
content: encodePBBuffer(Gallery, gallery), content: Gallery.encode(gallery).finish(),
}); });
await commitAssets('glossary', changes); await commitAssets('glossary', changes);
+1 -2
View File
@@ -21,7 +21,6 @@ import { gameModeBanners } from './gameModeBanners';
import { glossary } from './glossary'; import { glossary } from './glossary';
import { migration } from './migration'; import { migration } from './migration';
import { moduleIcons } from './moduleIcons'; import { moduleIcons } from './moduleIcons';
import { popularTanks } from './popularTanks';
import { shellIcons } from './shellIcons'; import { shellIcons } from './shellIcons';
import { skillIcons } from './skillIcons'; import { skillIcons } from './skillIcons';
import { tankArmors } from './tankArmors'; import { tankArmors } from './tankArmors';
@@ -47,7 +46,7 @@ const methods = [
boosterIcons, boosterIcons,
tankIcons, tankIcons,
blitzkitTankIcons, blitzkitTankIcons,
popularTanks, // popularTanks,
glossary, glossary,
]; ];
@@ -32,7 +32,7 @@ export async function migration() {
await commitAssets('migration', [ await commitAssets('migration', [
{ {
path: 'definitions/migration.json', path: 'definitions/migration.json',
content: Buffer.from(JSON.stringify(map)), content: new TextEncoder().encode(JSON.stringify(map)),
}, },
]); ]);
} }
@@ -1,6 +1,5 @@
import { import {
assertSecret, assertSecret,
encodePBBuffer,
fetchTankDefinitions, fetchTankDefinitions,
PopularTanks, PopularTanks,
} from '@blitzkit/core'; } from '@blitzkit/core';
@@ -70,7 +69,7 @@ export async function popularTanks() {
await commitAssets('popular tanks', [ await commitAssets('popular tanks', [
{ {
path: 'definitions/popular-tanks.pb', path: 'definitions/popular-tanks.pb',
content: encodePBBuffer(PopularTanks, popularTanks), content: PopularTanks.encode(popularTanks).finish(),
}, },
]); ]);
} }
@@ -29,10 +29,11 @@ export async function tankArmors() {
const id = toUniqueId(nation, tank.id); const id = toUniqueId(nation, tank.id);
const model = await extractArmor(DATA, `${nation}-${tankKey}`); const model = await extractArmor(DATA, `${nation}-${tankKey}`);
const content = await nodeIO.writeBinary(model);
changes.push({ changes.push({
path: `3d/tanks/armor/${id}.glb`, path: `3d/tanks/armor/${id}.glb`,
content: Buffer.from(await nodeIO.writeBinary(model)), content,
}); });
}), }),
); );
+16 -19
View File
@@ -1,7 +1,7 @@
import { toUniqueId } from '@blitzkit/core'; import { toUniqueId } from '@blitzkit/core';
import { NodeIO } from '@gltf-transform/core'; import { NodeIO } from '@gltf-transform/core';
import { ALL_EXTENSIONS } from '@gltf-transform/extensions'; import { ALL_EXTENSIONS } from '@gltf-transform/extensions';
import { readdir } from 'fs/promises'; import { readdir, writeFile } from 'fs/promises';
import { extractModel } from '../core/blitz/extractModel'; import { extractModel } from '../core/blitz/extractModel';
import { readXMLDVPL } from '../core/blitz/readXMLDVPL'; import { readXMLDVPL } from '../core/blitz/readXMLDVPL';
import { readYAMLDVPL } from '../core/blitz/readYAMLDVPL'; import { readYAMLDVPL } from '../core/blitz/readYAMLDVPL';
@@ -28,26 +28,23 @@ export async function tankModels() {
console.log(`Building models for ${nation}`); console.log(`Building models for ${nation}`);
await Promise.all( for (const [tankKey, tank] of Object.entries(tanks.root)) {
Object.entries(tanks.root).map(async ([tankKey, tank]) => { if (tankKey.includes('tutorial_bot')) continue;
if (tankKey.includes('tutorial_bot')) return;
const id = toUniqueId(nation, tank.id); const id = toUniqueId(nation, tank.id);
const parameters = await readYAMLDVPL<TankParameters>(
`${DATA}/3d/Tanks/Parameters/${nation}/${tankKey}.yaml`,
);
const model = await extractModel(
DATA,
parameters.resourcesPath.blitzModelPath.replace(/\.sc2$/, ''),
);
const parameters = await readYAMLDVPL<TankParameters>( changes.push({
`${DATA}/3d/Tanks/Parameters/${nation}/${tankKey}.yaml`, path: `3d/tanks/models/${id}.glb`,
); content: Buffer.from(await nodeIO.writeBinary(model)),
const model = await extractModel( });
DATA, }
parameters.resourcesPath.blitzModelPath.replace(/\.sc2$/, ''),
);
changes.push({
path: `3d/tanks/models/${id}.glb`,
content: Buffer.from(await nodeIO.writeBinary(model)),
});
}),
);
await commitAssets(`tank models ${nation}`, changes); await commitAssets(`tank models ${nation}`, changes);
} }
@@ -164,7 +164,7 @@ const content = RatingLeaderboard.encode({
const changes: FileChange[] = [ const changes: FileChange[] = [
{ {
path: `regions/${normalizedServer}/rating/${info.current_season}.pb`, path: `regions/${normalizedServer}/rating/${info.current_season}.pb`,
content: Buffer.from(content), content,
}, },
]; ];
+2 -2
View File
@@ -46,13 +46,13 @@ export function readDVPL(buffer: Buffer) {
source.length, source.length,
0, 0,
); );
if (decompressedSize !== footerData.oSize) { if (decompressedSize !== footerData.oSize) {
throw new RangeError( throw new RangeError(
`Decompressed DVPL size mismatch (${decompressedSize} vs ${footerData.oSize})`, `Decompressed DVPL size mismatch (${decompressedSize} vs ${footerData.oSize})`,
); );
} }
return Buffer.from(destination); return Buffer.from(destination);
} else { } else {
throw new SyntaxError('Unknown DVPL format'); throw new SyntaxError('Unknown DVPL format');
@@ -3,9 +3,19 @@ import { DATA_COMPRESSED } from '../../buildAssets/constants';
import { readDVPL } from './readDVPL'; import { readDVPL } from './readDVPL';
export async function readDVPLFile(file: string) { export async function readDVPLFile(file: string) {
if (DATA_COMPRESSED && !file.endsWith('.dvpl')) { let path: string;
return readDVPL(await readFile(`${file}.dvpl`));
if (DATA_COMPRESSED) {
path = file.endsWith('.dvpl') ? file : `${file}.dvpl`;
} else {
path = file.replace('.dvpl', '');
} }
return readFile(file); const content = await readFile(path);
if (!DATA_COMPRESSED) return content;
const dvpl = readDVPL(content);
return dvpl;
} }
@@ -1,16 +1,19 @@
import { DdsReadStream, PvrReadStream } from '@blitzkit/core'; import { DdsReadStream, PvrReadStream } from '@blitzkit/core';
import { existsSync } from 'fs'; import { existsSync } from 'fs';
import sharp from 'sharp'; import sharp from 'sharp';
import { DATA_COMPRESSED } from '../../../buildAssets/constants';
import { readDVPLFile } from '../readDVPLFile'; import { readDVPLFile } from '../readDVPLFile';
import { TextureMutation } from './constants'; import { TextureMutation } from './constants';
export async function readTexture(path: string, mutation?: TextureMutation) { export async function readTexture(path: string, mutation?: TextureMutation) {
const ddsTexturePath = path.replace('.tex', '.dx11.dds'); const ddsTexturePath = path.replace('.tex', '.dx11.dds');
const isDds = existsSync(`${ddsTexturePath}.dvpl`); const isDds = existsSync(
`${ddsTexturePath}${DATA_COMPRESSED ? '.dvpl' : ''}`,
);
const resolvedTexturePath = isDds const resolvedTexturePath = isDds
? ddsTexturePath ? ddsTexturePath
: ddsTexturePath.replace('.dds', '.pvr'); : ddsTexturePath.replace('.dds', '.pvr');
const decompressedDvpl = await readDVPLFile(resolvedTexturePath); const decompressedDvpl = await readDVPLFile(`${resolvedTexturePath}.dvpl`);
const raw = isDds const raw = isDds
? await new DdsReadStream(decompressedDvpl.buffer as ArrayBuffer).dds() ? await new DdsReadStream(decompressedDvpl.buffer as ArrayBuffer).dds()
@@ -1,10 +1,18 @@
import { asset } from '@blitzkit/core';
import ProgressBar from 'progress'; import ProgressBar from 'progress';
import { compareUint8Arrays } from './compareUint8Arrays';
import { GithubChangeBlob, createBlob } from './createBlob'; import { GithubChangeBlob, createBlob } from './createBlob';
import { octokit } from './octokit'; import { octokit } from './octokit';
export interface FileChange { export interface FileChange {
path: string; path: string;
content: Buffer; content: Uint8Array;
}
enum DiffStatus {
New,
Changed,
Unchanged,
} }
const heuristicFormats = ['glb', 'webp', 'jpg', 'png']; const heuristicFormats = ['glb', 'webp', 'jpg', 'png'];
@@ -19,72 +27,61 @@ export async function commitMultipleFiles(
await Promise.all( await Promise.all(
changesRaw.map(async (change) => { changesRaw.map(async (change) => {
const blobPath = `${repoRaw}/${branch}/${change.path}`; const response = await fetch(asset(change.path), {
const response = await fetch( headers: { 'Accept-Encoding': 'identity' },
`https://raw.githubusercontent.com/${blobPath}`, });
); let diff: { change: number; status: DiffStatus };
let isNew: boolean;
let isDifferent: boolean;
let diff: number;
if (response.status === 404) { if (response.status === 404) {
isNew = true; diff = { change: change.content.length, status: DiffStatus.New };
diff = change.content.length;
isDifferent = true;
} else if ( } else if (
response.headers.has('Content-Length') && response.headers.has('Content-Length') &&
parseInt(response.headers.get('Content-Length')!) !== Number(response.headers.get('Content-Length')) !== change.content.length
change.content.length
) { ) {
isNew = false; diff = {
diff = change:
change.content.length - change.content.length -
parseInt(response.headers.get('Content-Length')!); Number(response.headers.get('Content-Length')),
isDifferent = true; status: DiffStatus.Changed,
};
} else if (response.status === 200) { } else if (response.status === 200) {
isNew = false; if (
const buffer = Buffer.from(await response.arrayBuffer()); heuristicFormats.some((format) => change.path.endsWith(`.${format}`))
) {
if (buffer.equals(change.content)) { /**
diff = 0; * Heuristic: if it's a large blob like a .glb, a diff = 0 might end
isDifferent = false; * up being a false positive with isDifferent = true. So, it's okay
* to assume it's unchanged.
*/
diff = { change: 0, status: DiffStatus.Unchanged };
} else { } else {
diff = change.content.length - buffer.length; const buffer = new Uint8Array(await response.arrayBuffer());
isDifferent = true;
if (compareUint8Arrays(buffer, change.content)) {
diff = { change: 0, status: DiffStatus.Unchanged };
} else {
diff = {
change: change.content.length - buffer.length,
status: DiffStatus.Changed,
};
}
} }
} else { } else {
throw new Error( throw new Error(
`Unexpected status code ${response.status} for ${blobPath}`, `Unexpected status code ${response.status} for ${change.path}`,
); );
} }
/** if (diff.status === DiffStatus.Unchanged) {
* Heuristic: if it's a large blob like a .glb, a diff = 0 might end up // just don't bother
* being a false positive with isDifferent = true. So, it's okay to // console.log(`🔵 (${diff.change.toLocaleString()}B) ${change.path}`);
* assume it's unchanged.
*/
if (
diff === 0 &&
heuristicFormats.some((format) => change.path.endsWith(`.${format}`))
) {
isDifferent = false;
isNew = false;
}
if (isNew) {
console.log(
`🟢 (+${change.content.length.toLocaleString()}B) ${blobPath}`,
);
changes.push(change);
} else if (isDifferent) {
console.log(
`🟡 (${diff > 0 ? '+' : ''}${diff.toLocaleString()}B) ${blobPath}`,
);
changes.push(change);
} else { } else {
console.log( console.log(
`🔵 (${change.content.length.toLocaleString()}B) ${blobPath}`, `${
diff.status === DiffStatus.New ? '🟢' : '🟡'
} (${diff.change > 0 ? '+' : ''}${diff.change.toLocaleString()}B) ${change.path}`,
); );
changes.push(change);
} }
}), }),
); );
@@ -0,0 +1,9 @@
export function compareUint8Arrays(a: Uint8Array, b: Uint8Array) {
if (a.length !== b.length) return false;
for (let index = 0; index < a.length; index++) {
if (a[index] !== b[index]) return false;
}
return true;
}
@@ -20,7 +20,7 @@ export const createBlob = throttle(
await octokit.git.createBlob({ await octokit.git.createBlob({
owner, owner,
repo, repo,
content: change.content.toString('base64'), content: Buffer.from(change.content).toString('base64'),
encoding: 'base64', encoding: 'base64',
}) })
).data; ).data;
@@ -34,6 +34,7 @@ export const createBlob = throttle(
} catch (error) { } catch (error) {
console.warn( console.warn(
`Failed blob ${change.path}; retrying in ${TIME_PER_BLOB}ms...`, `Failed blob ${change.path}; retrying in ${TIME_PER_BLOB}ms...`,
error,
); );
await new Promise((resolve) => setTimeout(resolve, TIME_PER_BLOB)); await new Promise((resolve) => setTimeout(resolve, TIME_PER_BLOB));
+3 -6
View File
@@ -134,14 +134,12 @@ function post() {
const files = idsChunked.map((chunk, index) => { const files = idsChunked.map((chunk, index) => {
const didsWriteStream = new DidsWriteStream().dids(chunk); const didsWriteStream = new DidsWriteStream().dids(chunk);
const buffer = didsWriteStream.uint8Array; const buffer = didsWriteStream.uint8Array;
const compressed = compress(buffer); const content = compress(buffer);
console.log( console.log(
`Chunk ${index} with ${chunk.length} ids (compressed: ${compressed.length}; uncompressed: ${buffer.length})`, `Chunk ${index} with ${chunk.length} ids (compressed: ${content.length}; uncompressed: ${buffer.length})`,
); );
const content = Buffer.from(compressed);
return { return {
content, content,
path: `ids/${index}.dids.lz4`, path: `ids/${index}.dids.lz4`,
@@ -151,13 +149,12 @@ function post() {
commitAssets('discovered ids', [ commitAssets('discovered ids', [
...files, ...files,
{ {
content: Buffer.from( content: new TextEncoder().encode(
JSON.stringify({ JSON.stringify({
chunks: idsChunked.length, chunks: idsChunked.length,
count: ids.length, count: ids.length,
time: Date.now(), time: Date.now(),
} satisfies DiscoveredIdsDefinitions), } satisfies DiscoveredIdsDefinitions),
'utf-8',
), ),
path: 'ids/manifest.json', path: 'ids/manifest.json',
}, },
+1 -2
View File
@@ -1,6 +1,5 @@
import { import {
asset, asset,
encodePBBuffer,
fetchTankDefinitions, fetchTankDefinitions,
Reviews, Reviews,
Video, Video,
@@ -81,7 +80,7 @@ for (const tank of tanksSanitized) {
} }
await commitAssets('reviews', [ await commitAssets('reviews', [
{ {
content: encodePBBuffer(Reviews, reviews), content: Reviews.encode(reviews).finish(),
path: 'definitions/reviews.pb', path: 'definitions/reviews.pb',
}, },
]); ]);
+1 -2
View File
@@ -1,6 +1,5 @@
// @ts-check // @ts-check
import partytown from '@astrojs/partytown';
import react from '@astrojs/react'; import react from '@astrojs/react';
import sitemap from '@astrojs/sitemap'; import sitemap from '@astrojs/sitemap';
import { SUPPORTED_LOCALES } from '@blitzkit/i18n'; import { SUPPORTED_LOCALES } from '@blitzkit/i18n';
@@ -21,7 +20,7 @@ export default defineConfig({
outDir: '../../dist/website', outDir: '../../dist/website',
prefetch: true, prefetch: true,
integrations: [react(), sitemap(), partytown()], integrations: [react(), sitemap()],
vite: { vite: {
resolve: { resolve: {
alias: { alias: {
-1
View File
@@ -10,7 +10,6 @@
"astro": "astro" "astro": "astro"
}, },
"dependencies": { "dependencies": {
"@astrojs/partytown": "^2.1.4",
"@astrolib/seo": "^1.0.0-beta.8", "@astrolib/seo": "^1.0.0-beta.8",
"@blitzkit/core": "workspace:*", "@blitzkit/core": "workspace:*",
"@blitzkit/i18n": "workspace:*", "@blitzkit/i18n": "workspace:*",
@@ -0,0 +1 @@
dh=ecd11a058908f58ccea092ed17aa43ace59 4b9a5
@@ -23,7 +23,9 @@ export function AesonPlug() {
<Flex py="3" px="5" direction="column" justify="center"> <Flex py="3" px="5" direction="column" justify="center">
<Heading size="5">Preview brought to you by WoT Blitz News</Heading> <Heading size="5">Preview brought to you by WoT Blitz News</Heading>
<Text color="gray">What the hell do I put here haha</Text> <Text color="gray">
Join the Discord for the absolute latest news
</Text>
</Flex> </Flex>
</Flex> </Flex>
</Link> </Link>
@@ -1,3 +1,5 @@
precision mediump float;
#define USE_FOG #define USE_FOG
#include <fog_pars_fragment> #include <fog_pars_fragment>
@@ -1,3 +1,5 @@
precision mediump float;
#define USE_FOG #define USE_FOG
#include <fog_pars_vertex> #include <fog_pars_vertex>
@@ -1,3 +1,5 @@
precision mediump float;
uniform float thickness; uniform float thickness;
uniform float penetration; uniform float penetration;
@@ -1,3 +1,5 @@
precision mediump float;
#include <clipping_planes_pars_vertex> #include <clipping_planes_pars_vertex>
void main() { void main() {
@@ -1,3 +1,5 @@
precision mediump float;
varying vec3 vNormal; varying vec3 vNormal;
varying vec3 vViewPosition; varying vec3 vViewPosition;
@@ -1,3 +1,5 @@
precision mediump float;
varying vec3 vNormal; varying vec3 vNormal;
varying vec3 vViewPosition; varying vec3 vViewPosition;
@@ -79,6 +79,12 @@ export function Body({ stats }: BodyProps) {
<Table.Body> <Table.Body>
<CompareRow stats={stats} value="dpm" decimals={0} /> <CompareRow stats={stats} value="dpm" decimals={0} />
<CompareRow stats={stats} value="damage" decimals={0} />
{hasNonRegularGun && (
<CompareRow stats={stats} indent value="clipDamage" decimals={0} />
)}
<CompareRow stats={stats} value="moduleDamage" decimals={0} />
<CompareRow stats={stats} value="penetration" decimals={0} />
<CompareRow <CompareRow
stats={stats} stats={stats}
name={strings.website.tools.tankopedia.characteristics.values.reload} name={strings.website.tools.tankopedia.characteristics.values.reload}
@@ -105,12 +111,6 @@ export function Body({ stats }: BodyProps) {
<CompareRow stats={stats} value="shells" decimals={0} /> <CompareRow stats={stats} value="shells" decimals={0} />
</> </>
)} )}
<CompareRow stats={stats} value="penetration" decimals={0} />
<CompareRow stats={stats} value="damage" decimals={0} />
{hasNonRegularGun && (
<CompareRow stats={stats} indent value="clipDamage" decimals={0} />
)}
<CompareRow stats={stats} value="moduleDamage" decimals={0} />
<CompareRow stats={stats} value="caliber" decimals={0} /> <CompareRow stats={stats} value="caliber" decimals={0} />
<CompareRow stats={stats} value="shellNormalization" decimals={0} /> <CompareRow stats={stats} value="shellNormalization" decimals={0} />
<CompareRow <CompareRow
+7 -11
View File
@@ -8,7 +8,7 @@ import { LinkI18n } from './LinkI18n';
import { LocaleSwitcherThemeWrapper } from './LocaleSwitcher'; import { LocaleSwitcherThemeWrapper } from './LocaleSwitcher';
const gameDefinitions = await fetchGameDefinitions(); const gameDefinitions = await fetchGameDefinitions();
const PUBLIC_ASSET_BRANCH = assertSecret(import.meta.env.PUBLIC_ASSET_BRANCH); const PUBLIC_ASSET_BRANCH = assertSecret(import.meta.env.PUBLIC_BRANCH);
const locale = Astro.params.locale ?? DEFAULT_LOCALE; const locale = Astro.params.locale ?? DEFAULT_LOCALE;
const strings = getStrings(locale); const strings = getStrings(locale);
--- ---
@@ -127,34 +127,30 @@ const strings = getStrings(locale);
</Flex> </Flex>
</Flex> </Flex>
<Flex gap="5" display={{ initial: 'flex', sm: 'none' }}> <Flex gap="5" display={{ initial: 'flex', sm: 'none' }} width="100%">
<Flex direction="column" justify="between" align="end"> <Flex direction="column" gap="1" flexGrow="1" flexBasis="0" align="end">
<Text size="2" color="gray">BlitzKit</Text> <Text size="2" color="gray">BlitzKit</Text>
{ {
PUBLIC_ASSET_BRANCH !== 'opentest' && ( PUBLIC_ASSET_BRANCH !== 'preview' && (
<Text size="2" color="gray"> <Text size="2" color="gray">
WoTB WoTB
</Text> </Text>
) )
} }
<Text size="2" color="gray">CDN</Text> <Text size="2" color="gray">CDN</Text>
</Flex> </Flex>
<Flex direction="column" justify="between" align="start"> <Flex direction="column" gap="1" flexGrow="1" flexBasis="0" align="start">
<Code size="2" color="gray"> <Code size="2" color="gray">
{packageJson.version} {packageJson.version}
</Code> </Code>
{ {
PUBLIC_ASSET_BRANCH !== 'opentest' && ( PUBLIC_ASSET_BRANCH !== 'preview' && (
<Code size="2" color="gray"> <Code size="2" color="gray">
{gameDefinitions.version} {gameDefinitions.version}
</Code> </Code>
) )
} }
<Code size="2" color="gray"> <Code size="2" color="gray">
{PUBLIC_ASSET_BRANCH} {PUBLIC_ASSET_BRANCH}
</Code> </Code>
@@ -168,7 +164,7 @@ const strings = getStrings(locale);
</Code> </Code>
{ {
PUBLIC_ASSET_BRANCH !== 'opentest' && ( PUBLIC_ASSET_BRANCH !== 'preview' && (
<> <>
<Text size="2" color="gray"> <Text size="2" color="gray">
WoTB WoTB
+6 -5
View File
@@ -17,7 +17,7 @@ export interface Props {
integrated?: boolean; integrated?: boolean;
} }
const { integrated } = Astro.props; const { integrated = false } = Astro.props;
const toolsFiltered = TOOLS.filter((tool) => !('href' in tool)); const toolsFiltered = TOOLS.filter((tool) => !('href' in tool));
const { locale } = Astro.params; const { locale } = Astro.params;
const branchName = resolveBranchName(locale); const branchName = resolveBranchName(locale);
@@ -47,7 +47,7 @@ const strings = getStrings(locale);
height: 100%; height: 100%;
} }
.navbar[data-expanded='false'] .content { .navbar[data-expanded='false'][data-integrated='false'] .content {
background-color: var(--black-a8); background-color: var(--black-a8);
backdrop-filter: blur(4rem); backdrop-filter: blur(4rem);
box-shadow: var(--shadow-3); box-shadow: var(--shadow-3);
@@ -87,6 +87,7 @@ const strings = getStrings(locale);
direction="column" direction="column"
align="center" align="center"
data-expanded="false" data-expanded="false"
data-integrated={`${integrated}`}
className="navbar" className="navbar"
width="100%" width="100%"
top="0" top="0"
@@ -139,7 +140,7 @@ const strings = getStrings(locale);
toolsFiltered.map((tool) => { toolsFiltered.map((tool) => {
const unavailableOnBranch = tool.branches?.every( const unavailableOnBranch = tool.branches?.every(
(branch) => (branch) =>
branch !== assertSecret(import.meta.env.PUBLIC_ASSET_BRANCH), branch !== assertSecret(import.meta.env.PUBLIC_BRANCH),
); );
const selected = Astro.url.pathname.includes(`/${tool.id}`); const selected = Astro.url.pathname.includes(`/${tool.id}`);
const toolStrings = const toolStrings =
@@ -211,7 +212,7 @@ const strings = getStrings(locale);
toolsFiltered.map((tool) => { toolsFiltered.map((tool) => {
const unavailableOnBranch = tool.branches?.every( const unavailableOnBranch = tool.branches?.every(
(branch) => (branch) =>
branch !== assertSecret(import.meta.env.PUBLIC_ASSET_BRANCH), branch !== assertSecret(import.meta.env.PUBLIC_BRANCH),
); );
if (unavailableOnBranch) return null; if (unavailableOnBranch) return null;
@@ -232,7 +233,7 @@ const strings = getStrings(locale);
<Box <Box
style={{ style={{
borderRadius: Var('radius-2'), borderRadius: Var('radius-2'),
backgroundImage: `url(/assets/images/${tool.id}.webp)`, backgroundImage: `url(/assets/images/tools/${tool.id}.webp)`,
backgroundSize: '200%', backgroundSize: '200%',
backgroundPosition: 'right center', backgroundPosition: 'right center',
}} }}
+4 -26
View File
@@ -6,42 +6,20 @@ const PUBLIC_GOOGLE_TAG_MANAGER_ID = assertSecret(
); );
--- ---
{/* google analytics */}
<script <script
is:inline is:inline
async async
type="text/partytown"
src={`https://www.googletagmanager.com/gtag/js?id=${PUBLIC_GOOGLE_TAG_MANAGER_ID}`} src={`https://www.googletagmanager.com/gtag/js?id=${PUBLIC_GOOGLE_TAG_MANAGER_ID}`}
></script> ></script>
<script
is:inline <script is:inline define:vars={{ PUBLIC_GOOGLE_TAG_MANAGER_ID }}>
define:vars={{ PUBLIC_GOOGLE_TAG_MANAGER_ID }}
type="text/partytown"
>
window.dataLayer = window.dataLayer || []; window.dataLayer = window.dataLayer || [];
function gtag() { function gtag() {
dataLayer.push(arguments); dataLayer.push(arguments);
} }
gtag('js', new Date()); gtag('js', new Date());
gtag('config', PUBLIC_GOOGLE_TAG_MANAGER_ID); gtag('config', PUBLIC_GOOGLE_TAG_MANAGER_ID);
</script> </script>
{/* nitro ads */}
{
/*
<script is:inline data-cfasync="false">
window.nitroAds = window.nitroAds || {
createAd: function () {
return new Promise((e) => {
window.nitroAds.queue.push(['createAd', arguments, e]);
});
},
addUserToken: function () {
window.nitroAds.queue.push(['addUserToken', arguments]);
},
queue: [],
};
</script>
*/
}
+1 -1
View File
@@ -14,7 +14,7 @@ export function Plugs() {
function Content() { function Content() {
const promoteOpentest = const promoteOpentest =
assertSecret(import.meta.env.PUBLIC_PROMOTE_OPENTEST) === 'true' && assertSecret(import.meta.env.PUBLIC_PROMOTE_OPENTEST) === 'true' &&
assertSecret(import.meta.env.PUBLIC_ASSET_BRANCH) !== 'opentest'; assertSecret(import.meta.env.PUBLIC_BRANCH) !== 'opentest';
const promotions = [promoteOpentest]; const promotions = [promoteOpentest];
if (promotions.every((promotion) => !promotion)) return null; if (promotions.every((promotion) => !promotion)) return null;
@@ -80,7 +80,7 @@ export const TankCard = forwardRef<HTMLSpanElement, TankCardProps>(
> >
<img <img
alt={unwrap(tank.name)} alt={unwrap(tank.name)}
src={asset(`icons/tanks/blitzkit/${tank.id}.webp`)} src={asset(`icons/tanks/big/${tank.id}.webp`)}
className="image" className="image"
draggable={false} draggable={false}
/> />
@@ -27,6 +27,7 @@ export function TankSearchCard({ tank, onSelect }: TankSearchCardProps) {
const gun = turret.guns.at(-1)!; const gun = turret.guns.at(-1)!;
const shell0 = gun.gun_type!.value.base.shells[0]; const shell0 = gun.gun_type!.value.base.shells[0];
const shell1 = gun.gun_type!.value.base.shells[1]; const shell1 = gun.gun_type!.value.base.shells[1];
const shell2 = gun.gun_type!.value.base.shells[2];
const tracks = tank.tracks.at(-1)!; const tracks = tank.tracks.at(-1)!;
const engine = tank.engines.at(-1)!; const engine = tank.engines.at(-1)!;
const tankModelDefinition = modelDefinitions.models[tank.id]; const tankModelDefinition = modelDefinitions.models[tank.id];
@@ -57,6 +58,8 @@ export function TankSearchCard({ tank, onSelect }: TankSearchCardProps) {
return shell0.penetration.near.toFixed(0); return shell0.penetration.near.toFixed(0);
case 'fire.premiumPenetration': case 'fire.premiumPenetration':
return shell1 ? shell1.penetration.near.toFixed(0) : '--'; return shell1 ? shell1.penetration.near.toFixed(0) : '--';
case 'fire.tertiaryPenetration':
return shell1 ? shell2.penetration.near.toFixed(0) : '--';
case 'fire.shellVelocity': case 'fire.shellVelocity':
return shell0.velocity.toFixed(0); return shell0.velocity.toFixed(0);
case 'fire.shellCapacity': case 'fire.shellCapacity':
@@ -21,27 +21,17 @@ export function SearchBar({ topResult, skeleton, onSelect }: SearchBarProps) {
const input = useRef<HTMLInputElement>(null); const input = useRef<HTMLInputElement>(null);
const performSearch = useCallback( const performSearch = useCallback(
debounce(() => { debounce(() => {
// tankFiltersStore.setState({ searching: false });
$tankFilters.setKey('searching', false); $tankFilters.setKey('searching', false);
if (!input.current) return; if (!input.current) return;
const sanitized = input.current.value.trim(); const sanitized = input.current.value.trim();
// tankFiltersStore.setState({ $tankFilters.setKey('search', sanitized.length === 0 ? null : sanitized);
// search: sanitized.length === 0 ? undefined : sanitized,
// });
$tankFilters.setKey(
'search',
sanitized.length === 0 ? undefined : sanitized,
);
}, 500), }, 500),
[], [],
); );
const handleChange = useCallback(() => { const handleChange = useCallback(() => {
// if (!tankFiltersStore.getState().searching) {
// tankFiltersStore.setState({ searching: true });
// }
if (!tankFilters.searching) { if (!tankFilters.searching) {
$tankFilters.setKey('searching', true); $tankFilters.setKey('searching', true);
} }
@@ -69,7 +59,7 @@ export function SearchBar({ topResult, skeleton, onSelect }: SearchBarProps) {
<TextField.Root <TextField.Root
variant="classic" variant="classic"
disabled={skeleton} disabled={skeleton}
defaultValue={tankFilters.search} defaultValue={tankFilters.search ?? undefined}
style={{ flex: 1 }} style={{ flex: 1 }}
ref={input} ref={input}
placeholder={strings.website.common.tank_search.search_bar_hint} placeholder={strings.website.common.tank_search.search_bar_hint}
@@ -63,6 +63,7 @@ export function Sort() {
<Item by="fire.caliber" /> <Item by="fire.caliber" />
<Item by="fire.standardPenetration" /> <Item by="fire.standardPenetration" />
<Item by="fire.premiumPenetration" /> <Item by="fire.premiumPenetration" />
<Item by="fire.tertiaryPenetration" />
<Item by="fire.damage" /> <Item by="fire.damage" />
<Item by="fire.moduleDamage" /> <Item by="fire.moduleDamage" />
<Item by="fire.shellVelocity" /> <Item by="fire.shellVelocity" />
@@ -60,7 +60,7 @@ export const TankSearch = memo<TankSearchProps>(
const tankFilters = useStore($tankFilters); const tankFilters = useStore($tankFilters);
const tankopediaSort = useStore($tankopediaSort); const tankopediaSort = useStore($tankopediaSort);
const tanksFiltered = useMemo(() => { const tanksFiltered = useMemo(() => {
if (tankFilters.search === undefined) { if (tankFilters.search === null) {
const filtered = awaitedTanksDefinitionsArray.filter((tank) => const filtered = awaitedTanksDefinitionsArray.filter((tank) =>
filterTank(tankFilters, tank), filterTank(tankFilters, tank),
); );
@@ -238,6 +238,16 @@ export const TankSearch = memo<TankSearchProps>(
); );
break; break;
case 'fire.tertiaryPenetration':
sorted = filtered.sort(
(a, b) =>
(a.turrets.at(-1)!.guns.at(-1)!.gun_type!.value.base.shells[2]
?.penetration.near ?? 0) -
(b.turrets.at(-1)!.guns.at(-1)!.gun_type!.value.base.shells[2]
?.penetration.near ?? 0),
);
break;
case 'fire.damage': case 'fire.damage':
sorted = filtered.sort( sorted = filtered.sort(
(a, b) => (a, b) =>
@@ -15,7 +15,7 @@ export function CalloutsSection() {
const tank = Duel.use((state) => state.protagonist.tank); const tank = Duel.use((state) => state.protagonist.tank);
const mutateTankopediaPersistent = TankopediaPersistent.useMutation(); const mutateTankopediaPersistent = TankopediaPersistent.useMutation();
const promoteAeson = const promoteAeson =
assertSecret(import.meta.env.PUBLIC_ASSET_BRANCH) === 'preview'; assertSecret(import.meta.env.PUBLIC_BRANCH) === 'preview';
useEffect(() => { useEffect(() => {
mutateTankopediaPersistent((draft) => { mutateTankopediaPersistent((draft) => {
@@ -0,0 +1,7 @@
#assault-cursor {
cursor: grab;
}
#assault-cursor:active {
cursor: grabbing;
}
@@ -0,0 +1,113 @@
import { DragHandleDots2Icon } from '@radix-ui/react-icons';
import { Box, Flex, Text } from '@radix-ui/themes';
import { useEffect, useRef, useState } from 'react';
import { clamp } from 'three/src/math/MathUtils.js';
import {
fakeLog,
fakeLogInverse,
} from '../../../../../../../../../core/blitzkit/fakeLog';
import { Var } from '../../../../../../../../../core/radix/var';
import { Duel } from '../../../../../../../../../stores/duel';
import './index.css';
interface Props {
maxDistance: number;
maxFakeDistance: number;
}
export function AssaultCursor({ maxDistance, maxFakeDistance }: Props) {
const assaultDistance = Duel.use(
(state) => state.protagonist.assaultDistance,
);
const [x, setX] = useState(fakeLog(assaultDistance / maxDistance, 2));
const cursor = useRef<HTMLDivElement>(null);
const mutateDuel = Duel.useMutation();
useEffect(() => {
let localX = x;
function handlePointerDown(event: PointerEvent) {
event.preventDefault();
window.addEventListener('pointermove', handlePointerMove);
window.addEventListener('pointerup', handlePointerUp);
}
function handlePointerMove(event: PointerEvent) {
const parent = cursor.current?.parentElement;
if (!parent) return;
const width = parent.clientWidth;
setX((state) => {
localX = clamp(state + event.movementX / width, 0, 1);
return localX;
});
}
function handlePointerUp() {
mutateDuel((draft) => {
draft.protagonist.assaultDistance =
fakeLogInverse(localX * maxFakeDistance, 2) * maxDistance;
});
window.removeEventListener('pointermove', handlePointerMove);
window.removeEventListener('pointerup', handlePointerUp);
}
cursor.current?.addEventListener('pointerdown', handlePointerDown);
return () => {
cursor.current?.removeEventListener('pointerdown', handlePointerDown);
};
}, []);
return (
<Box
ref={cursor}
position="absolute"
top="0"
left={`${x * 100}%`}
height="100%"
width="2pt"
id="assault-cursor"
style={{
transform: 'translateX(-50%)',
backgroundColor: Var('accent-11'),
}}
>
<Flex
align="center"
direction="column"
position="absolute"
left="50%"
bottom="100%"
style={{ transform: 'translateX(-50%)' }}
>
<Flex
align="center"
justify="center"
style={{
width: '1.5rem',
height: '1.5rem',
backgroundColor: Var('accent-9'),
borderRadius: `50% 50% ${Var('radius-1')} ${Var('radius-1')}`,
}}
>
<Text style={{ display: 'flex' }} highContrast color="purple">
<DragHandleDots2Icon />
</Text>
</Flex>
<Box
height="0.5rem"
width="2pt"
style={{
backgroundColor: Var('accent-11'),
}}
/>
</Flex>
</Box>
);
}
@@ -0,0 +1,152 @@
import type { AssaultRanges } from '@blitzkit/core';
import { literals } from '@blitzkit/i18n';
import { Box, Card, Flex, Text } from '@radix-ui/themes';
import { clamp } from 'three/src/math/MathUtils.js';
import { fakeLog } from '../../../../../../../core/blitzkit/fakeLog';
import type { TankCharacteristics } from '../../../../../../../core/blitzkit/tankCharacteristics';
import { Var } from '../../../../../../../core/radix/var';
import { useLocale } from '../../../../../../../hooks/useLocale';
import { AssaultCursor } from './components/Cursor';
interface Props {
ranges: AssaultRanges;
stats: TankCharacteristics;
}
export function AssaultRangesVisualizer({ ranges: _ranges, stats }: Props) {
const maxDistance = _ranges.ranges.at(-1)!.distance;
const ranges = _ranges.ranges.map((range) => ({
factor: range.factor,
distance: range.distance,
fakeDistance: fakeLog(range.distance / maxDistance, 2),
}));
const maxFakeDistance = ranges.at(-1)!.fakeDistance;
const { strings } = useLocale();
return (
<Card mb="6" variant="classic" style={{ aspectRatio: '1 / 1' }}>
<Flex
position="absolute"
top="0"
left="0"
width="100%"
height="100%"
direction="column"
>
<Text m="3" size="2" color="gray">
{strings.website.tools.tankopedia.visualizers.assault.title}
</Text>
<Flex
direction="column"
p="3"
pt="8"
pr="5"
style={{ backgroundColor: Var('gray-1') }}
flexGrow="1"
>
<Flex flexGrow="1">
<Box position="relative" width={Var('space-8')}>
{ranges.map((range, index) => (
<Text
key={index}
style={{
position: 'absolute',
left: 0,
top: `${(1 - range.factor) * 100}%`,
transform: 'translateY(-50%)',
}}
color="gray"
size="1"
wrap="nowrap"
>
{literals(strings.common.units.hp, [
`${Math.round(stats.damageWithoutAssault * range.factor)}`,
])}
</Text>
))}
</Box>
<Flex flexGrow="1" align="end" position="relative">
{ranges.map((range, index) => {
const mix = clamp(1.5 * (range.factor - 1) + 1, 0, 1) * 100;
const color0 = `color-mix(in hsl, ${Var('tomato-9')}, ${Var('jade-9')} ${mix}%)`;
const color1 = `color-mix(in hsl, ${Var('tomato-7')}, ${Var('jade-7')} ${mix}%)`;
const last = ranges[index - 1];
const lastFakeDistance = last?.fakeDistance ?? 0;
const fakeWidth = range.fakeDistance - lastFakeDistance;
const fraction = fakeWidth / ranges.at(-1)!.fakeDistance;
return (
<Box
width={`${fraction * 100}%`}
height={`${range.factor * 100}%`}
style={{
background: `linear-gradient(45deg, ${color1}, ${color0})`,
}}
key={index}
/>
);
})}
{ranges.map((range, index) => (
<Box
key={index}
position="absolute"
left="0"
bottom={`${range.factor * 100}%`}
width="100%"
height="1pt"
style={{
transform: 'translateY(50%)',
backgroundColor: Var('gray-11'),
}}
/>
))}
<AssaultCursor
maxDistance={maxDistance}
maxFakeDistance={maxFakeDistance}
/>
</Flex>
</Flex>
<Flex ml="8" height={Var('space-7')}>
{ranges.map((range, index) => {
const last = ranges[index - 1];
const lastFakeDistance = last?.fakeDistance ?? 0;
const fakeWidth = range.fakeDistance - lastFakeDistance;
const fraction = fakeWidth / ranges.at(-1)!.fakeDistance;
return (
<Box
position="relative"
key={index}
width={`${fraction * 100}%`}
height="100%"
>
<Text
size="1"
color="gray"
mt="2"
style={{
position: 'absolute',
right: 0,
transform: 'translateX(50%)',
writingMode: 'vertical-rl',
}}
>
{literals(strings.common.units.m, [
`${Math.round(range.distance)}`,
])}
</Text>
</Box>
);
})}
</Flex>
</Flex>
</Flex>
</Card>
);
}
@@ -21,6 +21,7 @@ import { useEquipment } from '../../../../../../hooks/useEquipment';
import { useLocale } from '../../../../../../hooks/useLocale'; import { useLocale } from '../../../../../../hooks/useLocale';
import { useTankModelDefinition } from '../../../../../../hooks/useTankModelDefinition'; import { useTankModelDefinition } from '../../../../../../hooks/useTankModelDefinition';
import { Duel } from '../../../../../../stores/duel'; import { Duel } from '../../../../../../stores/duel';
import { AssaultRangesVisualizer } from './AssaultRangesVisualizer';
import { Info } from './Info'; import { Info } from './Info';
import { InfoWithDelta } from './InfoWithDelta'; import { InfoWithDelta } from './InfoWithDelta';
import { RicochetVisualizer } from './RicochetVisualizer'; import { RicochetVisualizer } from './RicochetVisualizer';
@@ -112,6 +113,20 @@ export function Firepower({ stats }: StatsAcceptorProps) {
{strings.common.gun_types[gun.gun_type!.$case]} {strings.common.gun_types[gun.gun_type!.$case]}
</Info> </Info>
<InfoWithDelta stats={stats} decimals={0} value="dpm" /> <InfoWithDelta stats={stats} decimals={0} value="dpm" />
<InfoWithDelta stats={stats} decimals={0} value="damage" />
{gun.gun_type!.$case !== 'regular' && (
<InfoWithDelta stats={stats} indent decimals={0} value="clipDamage" />
)}
<InfoWithDelta stats={stats} decimals={0} value="moduleDamage" />
<InfoWithDelta stats={stats} decimals={0} value="penetration" />
{gun.gun_type!.value.base.assault_ranges?.types.includes(shell.type) && (
<AssaultRangesVisualizer
stats={stats}
ranges={gun.gun_type!.value.base.assault_ranges}
/>
)}
{gun.gun_type!.$case === 'auto_reloader' && ( {gun.gun_type!.$case === 'auto_reloader' && (
<InfoWithDelta stats={stats} decimals={0} indent value="dpmEffective" /> <InfoWithDelta stats={stats} decimals={0} indent value="dpmEffective" />
)} )}
@@ -172,7 +187,6 @@ export function Firepower({ stats }: StatsAcceptorProps) {
)} )}
{/* <ReloadVisualizer stats={stats} /> */} {/* <ReloadVisualizer stats={stats} /> */}
<InfoWithDelta stats={stats} decimals={0} value="penetration" />
{typeof shell.penetration !== 'number' && ( {typeof shell.penetration !== 'number' && (
<> <>
<InfoWithDelta <InfoWithDelta
@@ -240,11 +254,6 @@ export function Firepower({ stats }: StatsAcceptorProps) {
</Flex> </Flex>
</> </>
)} )}
<InfoWithDelta stats={stats} decimals={0} value="damage" />
{gun.gun_type!.$case !== 'regular' && (
<InfoWithDelta stats={stats} indent decimals={0} value="clipDamage" />
)}
<InfoWithDelta stats={stats} decimals={0} value="moduleDamage" />
{isExplosive(shell.type) && ( {isExplosive(shell.type) && (
<InfoWithDelta <InfoWithDelta
stats={stats} stats={stats}
@@ -65,6 +65,14 @@ export function InfoWithDelta({
: (stats[props.value] as number); : (stats[props.value] as number);
const delta = useDelta(uhWhatDoICallThisVariable); const delta = useDelta(uhWhatDoICallThisVariable);
const protagonistTank = Duel.use((state) => state.protagonist.tank); const protagonistTank = Duel.use((state) => state.protagonist.tank);
const shellIndex = Duel.use((state) =>
state.protagonist.gun.gun_type!.value.base.shells.indexOf(
state.protagonist.shell,
),
);
const equipmentMatrix = Duel.use(
(state) => state.protagonist.equipmentMatrix,
);
const others = useMemo(() => { const others = useMemo(() => {
const defaultSkills = createDefaultSkills(skillDefinitions); const defaultSkills = createDefaultSkills(skillDefinitions);
@@ -86,6 +94,10 @@ export function InfoWithDelta({
provisionDefinitions, provisionDefinitions,
); );
if (member.gun.gun_type!.value.base.shells[shellIndex] === undefined) {
return undefined;
}
return tankCharacteristics( return tankCharacteristics(
{ {
applyDynamicArmor: false, applyDynamicArmor: false,
@@ -97,8 +109,8 @@ export function InfoWithDelta({
provisions: member.provisions, provisions: member.provisions,
engine: member.engine, engine: member.engine,
gun: member.gun, gun: member.gun,
equipmentMatrix: member.equipmentMatrix, equipmentMatrix: equipmentMatrix,
shell: member.shell, shell: member.gun.gun_type!.value.base.shells[shellIndex],
stockEngine: tank.engines[0], stockEngine: tank.engines[0],
stockGun: tank.turrets[0].guns[0], stockGun: tank.turrets[0].guns[0],
stockTrack: tank.tracks[0], stockTrack: tank.tracks[0],
@@ -106,6 +118,7 @@ export function InfoWithDelta({
tank, tank,
track: member.track, track: member.track,
turret: member.turret, turret: member.turret,
assaultDistance: member.assaultDistance,
}, },
{ {
equipmentDefinitions, equipmentDefinitions,
@@ -115,14 +128,16 @@ export function InfoWithDelta({
); );
}) })
.filter((tank) => { .filter((tank) => {
if (tank === undefined) return false;
const othersValue = const othersValue =
typeof props.value === 'function' typeof props.value === 'function'
? props.value(tank)! ? props.value(tank)!
: (tank[props.value] as number); : (tank[props.value] as number);
return othersValue !== undefined; return othersValue !== undefined;
}); }) as TankCharacteristics[];
}, [relativeAgainst]); }, [relativeAgainst, shellIndex, equipmentMatrix]);
const betterTanks = others.filter((tank) => { const betterTanks = others.filter((tank) => {
const othersValue = const othersValue =
typeof props.value === 'function' typeof props.value === 'function'
@@ -24,6 +24,9 @@ export function Characteristics() {
const provisions = Duel.use((state) => state.protagonist.provisions); const provisions = Duel.use((state) => state.protagonist.provisions);
const consumables = Duel.use((state) => state.protagonist.consumables); const consumables = Duel.use((state) => state.protagonist.consumables);
const camouflage = Duel.use((state) => state.protagonist.camouflage); const camouflage = Duel.use((state) => state.protagonist.camouflage);
const assaultDistance = Duel.use(
(state) => state.protagonist.assaultDistance,
);
const equipmentMatrix = Duel.use( const equipmentMatrix = Duel.use(
(state) => state.protagonist.equipmentMatrix, (state) => state.protagonist.equipmentMatrix,
); );
@@ -58,6 +61,7 @@ export function Characteristics() {
applyReactiveArmor: false, applyReactiveArmor: false,
applyDynamicArmor: false, applyDynamicArmor: false,
applySpallLiner: false, applySpallLiner: false,
assaultDistance,
}, },
{ {
tankModelDefinition, tankModelDefinition,
@@ -0,0 +1,25 @@
import { Box, Progress } from '@radix-ui/themes';
import { useProgress } from '@react-three/drei';
interface Props {
fontSize?: string;
}
export function Tracker({ fontSize }: Props) {
const { loaded, total } = useProgress();
const progress = total === 0 ? 0 : (loaded / total) * 100;
return (
<Box
position="absolute"
left="50%"
bottom="0"
width="min(100%, 16rem)"
style={{
transform: `translate(-50%, calc(${fontSize} / 2))`,
}}
>
<Progress color="gray" value={progress} />
</Box>
);
}
@@ -1,13 +1,14 @@
import { TankType } from '@blitzkit/core'; import { TankType } from '@blitzkit/core';
import { Box, Heading } from '@radix-ui/themes'; import { Box, Heading } from '@radix-ui/themes';
import { Var } from '../../../../../core/radix/var'; import { Var } from '../../../../../../core/radix/var';
import { useLocale } from '../../../../../hooks/useLocale'; import { useLocale } from '../../../../../../hooks/useLocale';
import { Duel } from '../../../../../stores/duel'; import { Duel } from '../../../../../../stores/duel';
import type { RadixColor } from '../../../../../stores/embedState'; import type { RadixColor } from '../../../../../../stores/embedState';
import { TankopediaEphemeral } from '../../../../../stores/tankopediaEphemeral'; import { TankopediaEphemeral } from '../../../../../../stores/tankopediaEphemeral';
import { Tracker } from './components/Tracker';
interface TitleProps { interface TitleProps {
outline?: boolean; foreground?: boolean;
} }
export const NATION_COLORS: Record< export const NATION_COLORS: Record<
@@ -65,7 +66,7 @@ export const NATION_COLORS: Record<
}, },
}; };
export function Title({ outline }: TitleProps) { export function Title({ foreground }: TitleProps) {
const { unwrap } = useLocale(); const { unwrap } = useLocale();
const protagonist = Duel.use((state) => state.protagonist.tank); const protagonist = Duel.use((state) => state.protagonist.tank);
const disturbed = TankopediaEphemeral.use((state) => state.disturbed); const disturbed = TankopediaEphemeral.use((state) => state.disturbed);
@@ -81,6 +82,11 @@ export function Title({ outline }: TitleProps) {
: `${nationColors.text}-12`, : `${nationColors.text}-12`,
); );
const name = unwrap(protagonist.name); const name = unwrap(protagonist.name);
const fontSize = revealed
? disturbed
? '2rem'
: `min(65vh, ${125 / name.length}vw)`
: `min(48vh, ${75 / name.length}vw)`;
return ( return (
<Box <Box
@@ -97,17 +103,10 @@ export function Title({ outline }: TitleProps) {
fontWeight: 900, fontWeight: 900,
userSelect: 'none', userSelect: 'none',
pointerEvents: 'none', pointerEvents: 'none',
fontSize: revealed fontSize,
? disturbed
? '2rem'
: `min(65vh, ${125 / name.length}vw)`
: `min(48vh, ${75 / name.length}vw)`,
whiteSpace: 'nowrap', whiteSpace: 'nowrap',
color: outline ? Var(`${nationColors.tint}-a2`) : color, color: foreground ? Var('gray-a10') : color,
opacity: outline && disturbed ? 0 : 1, opacity: foreground && disturbed ? 0 : 1,
WebkitTextStroke: outline
? `${revealed ? (disturbed ? '1px' : 'min(2px, 0.2vw)') : 0} ${color}`
: undefined,
letterSpacing: disturbed || !revealed ? 0 : '-0.03em', letterSpacing: disturbed || !revealed ? 0 : '-0.03em',
transition: ` transition: `
letter-spacing 1.5s ${disturbed ? '' : 'cubic-bezier(.81,-2,.68,1)'}, letter-spacing 1.5s ${disturbed ? '' : 'cubic-bezier(.81,-2,.68,1)'},
@@ -120,6 +119,8 @@ export function Title({ outline }: TitleProps) {
> >
{name} {name}
</Heading> </Heading>
{!revealed && <Tracker fontSize={fontSize} />}
</Box> </Box>
); );
} }
@@ -73,6 +73,9 @@ export function SceneProps() {
const crewSkills = TankopediaEphemeral.use((state) => state.skills); const crewSkills = TankopediaEphemeral.use((state) => state.skills);
const consumables = Duel.use((state) => state.protagonist.consumables); const consumables = Duel.use((state) => state.protagonist.consumables);
const provisions = Duel.use((state) => state.protagonist.provisions); const provisions = Duel.use((state) => state.protagonist.provisions);
const assaultDistance = Duel.use(
(state) => state.protagonist.assaultDistance,
);
const equipmentMatrix = Duel.use( const equipmentMatrix = Duel.use(
(state) => state.protagonist.equipmentMatrix, (state) => state.protagonist.equipmentMatrix,
); );
@@ -96,6 +99,7 @@ export function SceneProps() {
stockTurret: tank.turrets[0], stockTurret: tank.turrets[0],
stockTrack: tank.tracks[0], stockTrack: tank.tracks[0],
track, track,
assaultDistance,
}, },
{ equipmentDefinitions, provisionDefinitions, tankModelDefinition }, { equipmentDefinitions, provisionDefinitions, tankModelDefinition },
); );
@@ -1,3 +1,5 @@
precision mediump float;
#define USE_FOG #define USE_FOG
#include <fog_pars_fragment> #include <fog_pars_fragment>
@@ -1,3 +1,5 @@
precision mediump float;
#define USE_FOG #define USE_FOG
#include <fog_pars_vertex> #include <fog_pars_vertex>
@@ -39,11 +39,11 @@ interface TankSandboxProps {
naked?: boolean; naked?: boolean;
} }
export const forNear0 = 20; export const forNear0 = 30;
export const fogFar0 = 25; export const fogFar0 = 50;
export const forNear1 = 0; export const forNear1 = 0;
export const fogFar1 = 0; export const fogFar1 = 0;
export const fogAnimationTime = 1.5; export const fogAnimationTime = 2.5;
export const TankSandbox = forwardRef<HTMLCanvasElement, TankSandboxProps>( export const TankSandbox = forwardRef<HTMLCanvasElement, TankSandboxProps>(
({ thicknessRange, naked }, ref) => { ({ thicknessRange, naked }, ref) => {
@@ -74,7 +74,7 @@ export const TankSandbox = forwardRef<HTMLCanvasElement, TankSandboxProps>(
const interval = setInterval(() => { const interval = setInterval(() => {
const t = (Date.now() - t0) / 1000; const t = (Date.now() - t0) / 1000;
const x = t / fogAnimationTime; const x = t / fogAnimationTime;
const y = Math.cbrt(-2 * Math.abs(x - 0.5)) + 1; const y = Math.sin(Math.PI * x);
const near = forNear0 + (forNear1 - forNear0) * y; const near = forNear0 + (forNear1 - forNear0) * y;
const far = fogFar0 + (fogFar1 - fogFar0) * y; const far = fogFar0 + (fogFar1 - fogFar0) * y;
@@ -103,7 +103,7 @@ export function HeroSection({ skeleton }: MaybeSkeletonComponentProps) {
transitionDuration: '1s', transitionDuration: '1s',
background: isFullScreen ? 'black' : undefined, background: isFullScreen ? 'black' : undefined,
}} }}
height={disturbed && !isFullScreen ? 'calc(100svh - 6rem)' : '100vh'} height={!isFullScreen ? 'calc(100svh - 6rem)' : '100vh'}
maxHeight={isFullScreen ? undefined : '60rem'} maxHeight={isFullScreen ? undefined : '60rem'}
maxWidth={isFullScreen ? undefined : '120rem'} maxWidth={isFullScreen ? undefined : '120rem'}
flexGrow="1" flexGrow="1"
@@ -136,7 +136,7 @@ export function HeroSection({ skeleton }: MaybeSkeletonComponentProps) {
height: '100%', height: '100%',
transitionDuration: '2s', transitionDuration: '2s',
opacity: revealed ? 1 : 0, opacity: revealed ? 1 : 0,
filter: disturbed ? undefined : `drop-shadow(0 0 2rem black)`, filter: disturbed ? undefined : `drop-shadow(0 0 1rem black)`,
}} }}
> >
<Suspense> <Suspense>
@@ -153,7 +153,7 @@ export function HeroSection({ skeleton }: MaybeSkeletonComponentProps) {
</Box> </Box>
</Box> </Box>
<Title outline /> <Title foreground />
</Flex> </Flex>
</Flex> </Flex>
); );
@@ -12,7 +12,7 @@ interface Props {
const { tool } = Astro.props; const { tool } = Astro.props;
const disabled = tool.branches?.every( const disabled = tool.branches?.every(
(branch) => branch !== assertSecret(import.meta.env.PUBLIC_ASSET_BRANCH), (branch) => branch !== assertSecret(import.meta.env.PUBLIC_BRANCH),
); );
const { locale } = Astro.params; const { locale } = Astro.params;
const strings = getStrings(locale); const strings = getStrings(locale);
@@ -108,7 +108,7 @@ const toolStrings =
disabled ? ( disabled ? (
<> <>
Unavailable on{' '} Unavailable on{' '}
<Code>{assertSecret(import.meta.env.PUBLIC_ASSET_BRANCH)}</Code> <Code>{assertSecret(import.meta.env.PUBLIC_BRANCH)}</Code>
</> </>
) : ( ) : (
toolStrings.description toolStrings.description
@@ -5,7 +5,7 @@ export function resolveBranchName(locale: string = DEFAULT_LOCALE) {
if (!(locale in STRINGS)) throw new Error(`Unsupported locale: ${locale}`); if (!(locale in STRINGS)) throw new Error(`Unsupported locale: ${locale}`);
const strings = STRINGS[locale as SupportedLocale]; const strings = STRINGS[locale as SupportedLocale];
const secret = assertSecret(import.meta.env.PUBLIC_ASSET_BRANCH); const secret = assertSecret(import.meta.env.PUBLIC_BRANCH);
if ( if (
assertSecret(import.meta.env.MODE) === 'development' && assertSecret(import.meta.env.MODE) === 'development' &&
@@ -0,0 +1,9 @@
const GAMMA = 1.2;
export function fakeLog(x: number, a = 1) {
return Math.sin((Math.PI / 2) * x) ** (1 / GAMMA);
}
export function fakeLogInverse(y: number, a = 1) {
return (2 / Math.PI) * Math.asin(y ** GAMMA);
}
@@ -1,12 +1,12 @@
import { fetchEquipmentDefinitions } from '@blitzkit/core';
import type { EquipmentMatrix } from '../../stores/duel'; import type { EquipmentMatrix } from '../../stores/duel';
import { awaitableEquipmentDefinitions } from '../awaitables/equipmentDefinitions';
export async function hasEquipment( export async function hasEquipment(
id: number, id: number,
equipmentPreset: string, equipmentPreset: string,
equipmentMatrix: EquipmentMatrix, equipmentMatrix: EquipmentMatrix,
) { ) {
const equipmentDefinitions = await fetchEquipmentDefinitions(); const equipmentDefinitions = await awaitableEquipmentDefinitions;
const preset = equipmentDefinitions.presets[equipmentPreset]; const preset = equipmentDefinitions.presets[equipmentPreset];
return preset.slots.some((slot, index) => { return preset.slots.some((slot, index) => {
const row = Math.floor(index / 3); const row = Math.floor(index / 3);
Loaded 100 of 112 files, more files were not shown because too many files have changed in this diff. Show more