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
111 changed files with 3170 additions and 2219 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,
}, },
]; ];
@@ -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);
@@ -46,6 +46,7 @@ export function tankCharacteristics(
applyReactiveArmor, applyReactiveArmor,
applyDynamicArmor, applyDynamicArmor,
applySpallLiner, applySpallLiner,
assaultDistance,
}: { }: {
tank: TankDefinition; tank: TankDefinition;
turret: TurretDefinition; turret: TurretDefinition;
@@ -65,6 +66,7 @@ export function tankCharacteristics(
applyReactiveArmor: boolean; applyReactiveArmor: boolean;
applyDynamicArmor: boolean; applyDynamicArmor: boolean;
applySpallLiner: boolean; applySpallLiner: boolean;
assaultDistance: number;
}, },
{ {
tankModelDefinition, tankModelDefinition,
@@ -157,7 +159,15 @@ export function tankCharacteristics(
[applyDynamicArmor, -0.1], [applyDynamicArmor, -0.1],
[applySpallLiner && shell.type === ShellType.HE, -0.2], [applySpallLiner && shell.type === ShellType.HE, -0.2],
); );
const moduleDamageCoefficient = coefficient([hasTungsten, 0.15]); const assaultDamageCoefficient =
gun.gun_type!.value.base.assault_ranges &&
gun.gun_type!.value.base.assault_ranges.types.includes(shell.type)
? (gun.gun_type!.value.base.assault_ranges.ranges.find(
({ distance }) => distance >= assaultDistance,
)?.factor ?? 0)
: 1;
const moduleDamageCoefficient =
coefficient([hasTungsten, 0.15]) * assaultDamageCoefficient;
const reloadCoefficient = const reloadCoefficient =
(coefficient([hasGunRammer, -0.05]) * (coefficient([hasGunRammer, -0.05]) *
coefficient([true, degressiveStat(loaderMastery)])) / coefficient([true, degressiveStat(loaderMastery)])) /
@@ -326,10 +336,13 @@ export function tankCharacteristics(
stockTurret.weight + stockTurret.weight +
stockGun.gun_type!.value.base.weight; stockGun.gun_type!.value.base.weight;
const resolvedEnginePower = engine.power * enginePowerCoefficient; const resolvedEnginePower = engine.power * enginePowerCoefficient;
const damageCoefficientWithoutAssault = armorDamageCoefficient;
const damageCoefficient =
damageCoefficientWithoutAssault * assaultDamageCoefficient;
const dpm = resolveDpm( const dpm = resolveDpm(
gun, gun,
shell, shell,
armorDamageCoefficient, damageCoefficient,
reloadCoefficient, reloadCoefficient,
intraClipCoefficient, intraClipCoefficient,
); );
@@ -352,7 +365,9 @@ export function tankCharacteristics(
return current; return current;
}, null)!.index }, null)!.index
: undefined; : undefined;
const damage = shell.armor_damage * armorDamageCoefficient; const damageWithoutAssault =
shell.armor_damage * damageCoefficientWithoutAssault;
const damage = shell.armor_damage * damageCoefficient;
const dpmEffective = const dpmEffective =
gun.gun_type!.$case === 'auto_reloader' gun.gun_type!.$case === 'auto_reloader'
? gun.gun_type!.value.extension.shell_reloads[0] > ? gun.gun_type!.value.extension.shell_reloads[0] >
@@ -533,6 +548,7 @@ export function tankCharacteristics(
caliber, caliber,
penetration, penetration,
damage, damage,
damageWithoutAssault,
clipDamage, clipDamage,
moduleDamage, moduleDamage,
explosionRadius, explosionRadius,
Loaded 100 of 111 files, more files were not shown because too many files have changed in this diff. Show more