mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-11-13 20:56:11 +01:00
Compare commits
220
Commits
e5f7d72df3
...
v1.29.6
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
eed9d23646 | ||
|
|
2101dba7c6 | ||
|
|
1b398a5f66 | ||
|
|
d8f9a2633d | ||
|
|
2e79ccf7eb | ||
|
|
be778acf39 | ||
|
|
8d10d7cffa | ||
|
|
5b9041a972 | ||
|
|
1e60b1f61f | ||
|
|
13a636c023 | ||
|
|
8bc0693f3b | ||
|
|
9b842c501c | ||
|
|
8aadda4fb8 | ||
|
|
58c70f98e1 | ||
|
|
54b73d11ce | ||
|
|
d1ac5644a4 | ||
|
|
ae35c1516c | ||
|
|
fd364d434f | ||
|
|
fd37f72f8c | ||
|
|
1427f61c52 | ||
|
|
cd4fa366a0 | ||
|
|
344e7caa81 | ||
|
|
fe7b2aea02 | ||
|
|
fced1e96ef | ||
|
|
778efb2372 | ||
|
|
b67fd5b58c | ||
|
|
2559782a28 | ||
|
|
efb479fece | ||
|
|
fb829d4b81 | ||
|
|
91f4f2edcf | ||
|
|
a692d1ee0b | ||
|
|
31d2ab4746 | ||
|
|
e4e2c30748 | ||
|
|
d633874d90 | ||
|
|
9cb1d0cb3f | ||
|
|
a0bccc7973 | ||
|
|
3efe807e35 | ||
|
|
1cc15f64b0 | ||
|
|
f70864a0db | ||
|
|
5de40b220f | ||
|
|
bd19c9aac9 | ||
|
|
6bc5b7dcb6 | ||
|
|
00795eecdd | ||
|
|
f4e7b2ed98 | ||
|
|
81612793e3 | ||
|
|
d3bdbc39d2 | ||
|
|
7cb67bd44b | ||
|
|
9df09c9a53 | ||
|
|
a9f1d9ebec | ||
|
|
1b834eb848 | ||
|
|
c5518ec9bc | ||
|
|
8c705d7e2e | ||
|
|
efe9f91a2d | ||
|
|
e84bf6b31c | ||
|
|
46234b6cbb | ||
|
|
0bda743a91 | ||
|
|
b19866a1f5 | ||
|
|
9ca329e53f | ||
|
|
47b1eb9ab0 | ||
|
|
6c8fbf7245 | ||
|
|
2ea22512d4 | ||
|
|
697d1fa1b4 | ||
|
|
e4429f15bd | ||
|
|
cd8083ae30 | ||
|
|
9dcf7441c9 | ||
|
|
d4e1f99ce2 | ||
|
|
98de246578 | ||
|
|
45097f198c | ||
|
|
e063719caa | ||
|
|
975d579d21 | ||
|
|
b963ef0981 | ||
|
|
49fab21113 | ||
|
|
cbde48d41b | ||
|
|
1210baa545 | ||
|
|
2c03b530d2 | ||
|
|
ec977899fb | ||
|
|
e5fc2faad7 | ||
|
|
541dfc186b | ||
|
|
182471c4d6 | ||
|
|
e5c66cf232 | ||
|
|
fbbc0b82b4 | ||
|
|
aecc2adb07 | ||
|
|
f8ee2b64a6 | ||
|
|
7c4e28bd09 | ||
|
|
80d61d9e04 | ||
|
|
0c22ac3a97 | ||
|
|
efad6e61f7 | ||
|
|
3563aaecd5 | ||
|
|
5294de848f | ||
|
|
e82aa56cb2 | ||
|
|
e1b2b130a5 | ||
|
|
28f22f1d40 | ||
|
|
a3bb023309 | ||
|
|
797307fb81 | ||
|
|
f9802b44ff | ||
|
|
e26b9c78a3 | ||
|
|
925ae1a0b7 | ||
|
|
9584ecf38b | ||
|
|
338168d7e4 | ||
|
|
711d92887e | ||
|
|
78160041e8 | ||
|
|
1b884a52f9 | ||
|
|
f13c658ef4 | ||
|
|
b72d4058be | ||
|
|
029a781c50 | ||
|
|
adc1791f56 | ||
|
|
15b6ff43c5 | ||
|
|
e2c02f3d86 | ||
|
|
3ce47f6ed0 | ||
|
|
fa91b37d92 | ||
|
|
108644bd44 | ||
|
|
413436376b | ||
|
|
7d118015d0 | ||
|
|
92e7390a5d | ||
|
|
475e25a0d8 | ||
|
|
17115af0d8 | ||
|
|
a9894ade78 | ||
|
|
f5b09873a9 | ||
|
|
ac768d0897 | ||
|
|
f802b997c0 | ||
|
|
db94edea69 | ||
|
|
0809c9ee0c | ||
|
|
0326e8d1d7 | ||
|
|
912c1fb125 | ||
|
|
d07383a722 | ||
|
|
582e608203 | ||
|
|
501a618d5f | ||
|
|
7c7f34d899 | ||
|
|
864d34f344 | ||
|
|
9201fc72ce | ||
|
|
50f82d68b4 | ||
|
|
b81f664379 | ||
|
|
389707d0c8 | ||
|
|
9fbd623d91 | ||
|
|
f36df9e902 | ||
|
|
437bbfdc89 | ||
|
|
7becb7b6ad | ||
|
|
94e8a07f90 | ||
|
|
4ae5283ac4 | ||
|
|
ade238966b | ||
|
|
ea048da7a2 | ||
|
|
263f292a59 | ||
|
|
ff4a87e5b8 | ||
|
|
222b690fba | ||
|
|
e1a6e4e38d | ||
|
|
37adc04cda | ||
|
|
3fc7279f0e | ||
|
|
bd852b9368 | ||
|
|
26304fc281 | ||
|
|
0d8cb5c1ae | ||
|
|
dc60cffdff | ||
|
|
a3e74de277 | ||
|
|
49b5d4f7dc | ||
|
|
2c55455cd7 | ||
|
|
648ac57424 | ||
|
|
5e3cf816ee | ||
|
|
98ea42c7b0 | ||
|
|
873c8a54d3 | ||
|
|
927495ca16 | ||
|
|
cc957466fc | ||
|
|
ef173758aa | ||
|
|
bfceacdf3c | ||
|
|
ed0dde37d2 | ||
|
|
5ba64f231a | ||
|
|
1f06b1fef4 | ||
|
|
7b0625fc8d | ||
|
|
5dce234447 | ||
|
|
0f609717d0 | ||
|
|
3958709348 | ||
|
|
2d869c9fac | ||
|
|
82afaf9494 | ||
|
|
b1d82e624a | ||
|
|
9b60d56a36 | ||
|
|
ee0d4f6996 | ||
|
|
2d43408822 | ||
|
|
868f132105 | ||
|
|
ce428e093b | ||
|
|
ab430dc0ca | ||
|
|
03a51c47bb | ||
|
|
1790443698 | ||
|
|
a60f95340c | ||
|
|
e407463ca7 | ||
|
|
61cc15aafc | ||
|
|
1a947a6300 | ||
|
|
75262647f7 | ||
|
|
9914371dd8 | ||
|
|
a4e48a2feb | ||
|
|
4ab03e56a2 | ||
|
|
06a3791ddd | ||
|
|
36cce4b0c1 | ||
|
|
158141fdc7 | ||
|
|
1d319551e7 | ||
|
|
0552ac790e | ||
|
|
5ad7566874 | ||
|
|
638f178fbf | ||
|
|
1e996cb970 | ||
|
|
8639b31b8f | ||
|
|
889a92e98b | ||
|
|
e7fe3a4baf | ||
|
|
ab10343704 | ||
|
|
9412be2d7c | ||
|
|
66cf590f1c | ||
|
|
7c18549c00 | ||
|
|
9b97d3e27d | ||
|
|
aadc252e47 | ||
|
|
320a764d45 | ||
|
|
5594c0ec3b | ||
|
|
3d69d464f5 | ||
|
|
dd0b2bade7 | ||
|
|
99c90cfa9e | ||
|
|
dd3ce21508 | ||
|
|
b512cb2292 | ||
|
|
907e71ce03 | ||
|
|
10942879a6 | ||
|
|
d60551d30a | ||
|
|
b8c8528e1c | ||
|
|
0c9643016a | ||
|
|
61d1ebbad6 | ||
|
|
e9b7059cc0 | ||
|
|
a359897a2a |
No files matched your search
@@ -1,4 +1,4 @@
|
|||||||
name: Build Assets
|
name: Assets
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
@@ -6,30 +6,30 @@ on:
|
|||||||
|
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
inputs:
|
inputs:
|
||||||
cdn_branch:
|
asset_repo:
|
||||||
|
type: choice
|
||||||
|
required: false
|
||||||
|
description: What asset repo to write to
|
||||||
|
options:
|
||||||
|
- blitzkit/assets
|
||||||
|
- blitzkit/assets-preview
|
||||||
|
- blitzkit/assets-dev
|
||||||
|
default: blitzkit/assets
|
||||||
|
|
||||||
|
archive_url:
|
||||||
type: string
|
type: string
|
||||||
required: false
|
required: false
|
||||||
default: main
|
description: Archive URL to download instead of Steam client
|
||||||
description: What CDN branch to write to
|
|
||||||
zip_url:
|
|
||||||
type: string
|
|
||||||
required: false
|
|
||||||
description: ZIP URL to download instead of Steam client
|
|
||||||
zip_root:
|
|
||||||
type: string
|
|
||||||
required: false
|
|
||||||
description: Root dir of ZIP which houses the executable and Data dir
|
|
||||||
|
|
||||||
schedule:
|
schedule:
|
||||||
- cron: '0 2 * * *'
|
- cron: "0 2 * * *"
|
||||||
|
|
||||||
concurrency:
|
concurrency:
|
||||||
group: ${{ github.workflow }}-${{ github.ref }}-${{ github.event.inputs.cdn_branch }}
|
group: ${{ github.workflow }}-${{ github.ref }}-${{ github.event.inputs.asset_repo }}
|
||||||
cancel-in-progress: true
|
cancel-in-progress: true
|
||||||
|
|
||||||
env:
|
env:
|
||||||
DISCORD_CLIENT_ID: ${{ secrets.DISCORD_CLIENT_ID }}
|
DISCORD_CLIENT_ID: ${{ secrets.DISCORD_CLIENT_ID }}
|
||||||
GH_TOKEN: ${{ secrets.GH_TOKEN }}
|
|
||||||
DISCORD_TOKEN: ${{ secrets.DISCORD_TOKEN }}
|
DISCORD_TOKEN: ${{ secrets.DISCORD_TOKEN }}
|
||||||
DATABASE_URL: ${{ secrets.DATABASE_URL }}
|
DATABASE_URL: ${{ secrets.DATABASE_URL }}
|
||||||
VIDEOS_SHEET: ${{ secrets.VIDEOS_SHEET }}
|
VIDEOS_SHEET: ${{ secrets.VIDEOS_SHEET }}
|
||||||
@@ -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: blitzkit/assets
|
PUBLIC_ASSET_REPO: ${{ github.event.inputs.asset_repo != '' && github.event.inputs.asset_repo || secrets.PUBLIC_ASSET_REPO }}
|
||||||
PUBLIC_ASSET_BRANCH: main
|
PUBLIC_ASSET_BRANCH: ${{ secrets.PUBLIC_ASSET_BRANCH }}
|
||||||
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 }}
|
||||||
@@ -54,100 +54,28 @@ env:
|
|||||||
PUBLIC_ASSET_FAST_USER: blitzkit
|
PUBLIC_ASSET_FAST_USER: blitzkit
|
||||||
PUBLIC_ASSET_FAST_REPO: assets
|
PUBLIC_ASSET_FAST_REPO: assets
|
||||||
PUBLIC_ASSET_BASE: ${{ secrets.PUBLIC_ASSET_BASE }}
|
PUBLIC_ASSET_BASE: ${{ secrets.PUBLIC_ASSET_BASE }}
|
||||||
|
GH_TOKEN: ${{ secrets.GH_TOKEN }}
|
||||||
|
STEAM_USERNAME: ${{ secrets.STEAM_USERNAME }}
|
||||||
|
STEAM_PASSWORD: ${{ secrets.STEAM_PASSWORD }}
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
download_client:
|
|
||||||
name: Download client
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: (ZIP) Maximize build space
|
|
||||||
if: github.event.inputs.zip_url != ''
|
|
||||||
uses: easimon/maximize-build-space@master
|
|
||||||
with:
|
|
||||||
root-reserve-mb: 512
|
|
||||||
swap-size-mb: 1024
|
|
||||||
remove-dotnet: 'true'
|
|
||||||
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
submodules: recursive
|
|
||||||
token: ${{ secrets.GH_TOKEN }}
|
|
||||||
|
|
||||||
- name: (Steam) Setup bun
|
|
||||||
uses: oven-sh/setup-bun@v1
|
|
||||||
if: github.event.inputs.zip_url == ''
|
|
||||||
|
|
||||||
- name: (Steam) Install dependencies
|
|
||||||
if: github.event.inputs.zip_url == ''
|
|
||||||
run: bun install
|
|
||||||
|
|
||||||
- name: (Steam) Setup DepotDownloader
|
|
||||||
if: github.event.inputs.zip_url == ''
|
|
||||||
run: bun run setup:depotdownloader
|
|
||||||
|
|
||||||
- name: (Steam) Download client
|
|
||||||
if: github.event.inputs.zip_url == ''
|
|
||||||
run: |
|
|
||||||
chmod +x ./temp/depotDownloader/DepotDownloader
|
|
||||||
./temp/depotDownloader/DepotDownloader -q -os windows -app 444200 -username ${{ secrets.DEPOT_DOWNLOADER_USERNAME }} -password "${{ secrets.DEPOT_DOWNLOADER_PASSWORD }}"
|
|
||||||
|
|
||||||
- name: (Steam) Apply patches
|
|
||||||
if: github.event.inputs.zip_url == ''
|
|
||||||
run: bun setup:patches --depot
|
|
||||||
|
|
||||||
- name: (ZIP) Download client
|
|
||||||
if: github.event.inputs.zip_url != ''
|
|
||||||
env:
|
|
||||||
ZIP_URL: ${{ github.event.inputs.zip_url }}
|
|
||||||
ZIP_ROOT: ${{ github.event.inputs.zip_root }}
|
|
||||||
run: |
|
|
||||||
wget -q -O client.zip $ZIP_URL
|
|
||||||
unzip -q client.zip -d client
|
|
||||||
rm client.zip
|
|
||||||
mkdir -p depots/444202/0
|
|
||||||
mv client/$ZIP_ROOT/* depots/444202/0
|
|
||||||
|
|
||||||
- name: Archive depots
|
|
||||||
uses: actions/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
name: depots
|
|
||||||
path: depots
|
|
||||||
|
|
||||||
build_assets:
|
build_assets:
|
||||||
name: Build assets
|
name: Build assets
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
needs: download_client
|
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
submodules: recursive
|
submodules: recursive
|
||||||
token: ${{ secrets.GH_TOKEN }}
|
token: ${{ secrets.GH_TOKEN }}
|
||||||
|
- uses: arduino/setup-protoc@v3
|
||||||
- name: Setup bun
|
|
||||||
uses: oven-sh/setup-bun@v1
|
|
||||||
|
|
||||||
- name: Install dependencies
|
|
||||||
run: bun install
|
|
||||||
|
|
||||||
- name: Lint
|
|
||||||
run: bun run lint:website
|
|
||||||
|
|
||||||
- name: Download depots
|
|
||||||
uses: actions/download-artifact@v4
|
|
||||||
with:
|
with:
|
||||||
name: depots
|
repo-token: ${{ secrets.GH_TOKEN }}
|
||||||
path: depots
|
- uses: oven-sh/setup-bun@v1
|
||||||
|
- run: bun run setup
|
||||||
|
|
||||||
- name: AppArmor hack
|
- name: AppArmor hack
|
||||||
run: echo 0 | sudo tee /proc/sys/kernel/apparmor_restrict_unprivileged_userns
|
run: echo 0 | sudo tee /proc/sys/kernel/apparmor_restrict_unprivileged_userns
|
||||||
|
|
||||||
- name: Start server and build assets
|
- name: Build assets
|
||||||
run: |
|
run: bun run build:assets --all-targets --manual
|
||||||
bun dev:website --verbosepa &
|
|
||||||
SERVER_PID=$!
|
|
||||||
|
|
||||||
bun run build:assets --all-targets --depot --production
|
|
||||||
|
|
||||||
kill $SERVER_PID || true
|
|
||||||
@@ -3,7 +3,7 @@ name: Averages
|
|||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
schedule:
|
schedule:
|
||||||
- cron: '0 8 * * *'
|
- cron: "0 8 * * *"
|
||||||
|
|
||||||
concurrency:
|
concurrency:
|
||||||
group: ${{ github.workflow }}-${{ github.ref }}
|
group: ${{ github.workflow }}-${{ github.ref }}
|
||||||
@@ -15,7 +15,7 @@ env:
|
|||||||
PUBLIC_ASSET_FAST_USER: ${{ secrets.PUBLIC_ASSET_FAST_USER }}
|
PUBLIC_ASSET_FAST_USER: ${{ secrets.PUBLIC_ASSET_FAST_USER }}
|
||||||
PUBLIC_ASSET_FAST_REPO: ${{ secrets.PUBLIC_ASSET_FAST_REPO }}
|
PUBLIC_ASSET_FAST_REPO: ${{ secrets.PUBLIC_ASSET_FAST_REPO }}
|
||||||
PUBLIC_PROMOTE_OPENTEST: ${{ secrets.PUBLIC_PROMOTE_OPENTEST }}
|
PUBLIC_PROMOTE_OPENTEST: ${{ secrets.PUBLIC_PROMOTE_OPENTEST }}
|
||||||
ALLOW_ROBOTS: 'true'
|
ALLOW_ROBOTS: "true"
|
||||||
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 }}
|
||||||
@@ -25,6 +25,7 @@ env:
|
|||||||
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_ASSET_BASE: ${{ secrets.PUBLIC_ASSET_BASE }}
|
||||||
PUBLIC_BRANCH: ${{ secrets.PUBLIC_BRANCH }}
|
PUBLIC_BRANCH: ${{ secrets.PUBLIC_BRANCH }}
|
||||||
|
GH_TOKEN: ${{ secrets.GH_TOKEN }}
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
@@ -32,16 +33,20 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
submodules: recursive
|
||||||
|
token: ${{ secrets.GH_TOKEN }}
|
||||||
- uses: oven-sh/setup-bun@v1
|
- uses: oven-sh/setup-bun@v1
|
||||||
|
- uses: arduino/setup-protoc@v3
|
||||||
- name: Install dependencies
|
with:
|
||||||
run: bun install
|
repo-token: ${{ secrets.GH_TOKEN }}
|
||||||
|
- run: bun run setup
|
||||||
|
|
||||||
- name: Build averages
|
- name: Build averages
|
||||||
env:
|
env:
|
||||||
PUBLIC_ASSET_BRANCH: main
|
PUBLIC_ASSET_BRANCH: main
|
||||||
DISCORD_CLIENT_ID: ${{ secrets.DISCORD_CLIENT_ID }}
|
DISCORD_CLIENT_ID: ${{ secrets.DISCORD_CLIENT_ID }}
|
||||||
GH_TOKEN: ${{ secrets.GH_TOKEN }}
|
|
||||||
DISCORD_TOKEN: ${{ secrets.DISCORD_TOKEN }}
|
DISCORD_TOKEN: ${{ secrets.DISCORD_TOKEN }}
|
||||||
DATABASE_URL: ${{ secrets.DATABASE_URL }}
|
DATABASE_URL: ${{ secrets.DATABASE_URL }}
|
||||||
VIDEOS_SHEET: ${{ secrets.VIDEOS_SHEET }}
|
VIDEOS_SHEET: ${{ secrets.VIDEOS_SHEET }}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
name: Build Bot
|
name: Bot
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
@@ -15,13 +15,14 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
submodules: recursive
|
||||||
|
token: ${{ secrets.GH_TOKEN }}
|
||||||
- uses: oven-sh/setup-bun@v1
|
- uses: oven-sh/setup-bun@v1
|
||||||
|
- uses: arduino/setup-protoc@v3
|
||||||
- name: Install dependencies
|
with:
|
||||||
run: bun install
|
repo-token: ${{ secrets.GH_TOKEN }}
|
||||||
|
- run: bun run setup
|
||||||
- name: Build Prisma
|
|
||||||
run: bun run build:prisma
|
|
||||||
|
|
||||||
- name: Build bot
|
- name: Build bot
|
||||||
run: bun run build:bot
|
run: bun run build:bot
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
name: Discover IDs
|
name: IDs
|
||||||
|
|
||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
schedule:
|
schedule:
|
||||||
- cron: '0 0 * * 1'
|
- cron: "0 0 * * 1"
|
||||||
|
|
||||||
concurrency:
|
concurrency:
|
||||||
group: ${{ github.workflow }}-${{ github.ref }}
|
group: ${{ github.workflow }}-${{ github.ref }}
|
||||||
@@ -11,11 +11,11 @@ concurrency:
|
|||||||
|
|
||||||
env:
|
env:
|
||||||
DISCORD_TOKEN: ${{ secrets.DISCORD_TOKEN }}
|
DISCORD_TOKEN: ${{ secrets.DISCORD_TOKEN }}
|
||||||
GH_TOKEN: ${{ secrets.GH_TOKEN }}
|
|
||||||
DATABASE_URL: ${{ secrets.DATABASE_URL }}
|
DATABASE_URL: ${{ secrets.DATABASE_URL }}
|
||||||
PUBLIC_ASSET_BRANCH: ${{ secrets.PUBLIC_ASSET_BRANCH }}
|
PUBLIC_ASSET_BRANCH: ${{ secrets.PUBLIC_ASSET_BRANCH }}
|
||||||
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 }}
|
||||||
|
GH_TOKEN: ${{ secrets.GH_TOKEN }}
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
@@ -23,10 +23,14 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
submodules: recursive
|
||||||
|
token: ${{ secrets.GH_TOKEN }}
|
||||||
- uses: oven-sh/setup-bun@v1
|
- uses: oven-sh/setup-bun@v1
|
||||||
|
- uses: arduino/setup-protoc@v3
|
||||||
- name: Install dependencies
|
with:
|
||||||
run: bun install
|
repo-token: ${{ secrets.GH_TOKEN }}
|
||||||
|
- run: bun run setup
|
||||||
|
|
||||||
- name: Discover IDs
|
- name: Discover IDs
|
||||||
run: bun build:ids --production
|
run: bun build:ids --production
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
name: Host Bot
|
name: Host
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: main
|
branches: main
|
||||||
schedule:
|
schedule:
|
||||||
- cron: '0 */5 * * *'
|
- cron: "0 */5 * * *"
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
release:
|
release:
|
||||||
types: [created, published, released, edited]
|
types: [created, published, released, edited]
|
||||||
@@ -35,6 +35,7 @@ env:
|
|||||||
PUBLIC_BRANCH: ${{ secrets.PUBLIC_BRANCH }}
|
PUBLIC_BRANCH: ${{ secrets.PUBLIC_BRANCH }}
|
||||||
PUBLIC_GUIDE_WEBSITE: ${{ secrets.PUBLIC_GUIDE_WEBSITE }}
|
PUBLIC_GUIDE_WEBSITE: ${{ secrets.PUBLIC_GUIDE_WEBSITE }}
|
||||||
SERVICING: ${{ secrets.SERVICING }}
|
SERVICING: ${{ secrets.SERVICING }}
|
||||||
|
GH_TOKEN: ${{ secrets.GH_TOKEN }}
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
host:
|
host:
|
||||||
@@ -42,8 +43,9 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: oven-sh/setup-bun@v1
|
- uses: oven-sh/setup-bun@v1
|
||||||
# with:
|
- uses: arduino/setup-protoc@v3
|
||||||
# bun-version: 1.1.33
|
with:
|
||||||
|
repo-token: ${{ secrets.GH_TOKEN }}
|
||||||
|
|
||||||
- name: Download release assets
|
- name: Download release assets
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
@@ -3,7 +3,29 @@ name: Rating Asia
|
|||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
schedule:
|
schedule:
|
||||||
- cron: '0 17 * * *'
|
- cron: "0 17 * * *"
|
||||||
|
|
||||||
|
env:
|
||||||
|
PUBLIC_ASSET_BRANCH: main
|
||||||
|
PUBLIC_ASSET_REPO: ${{ secrets.PUBLIC_ASSET_REPO }}
|
||||||
|
DISCORD_CLIENT_ID: ${{ secrets.DISCORD_CLIENT_ID }}
|
||||||
|
DISCORD_TOKEN: ${{ secrets.DISCORD_TOKEN }}
|
||||||
|
DATABASE_URL: ${{ secrets.DATABASE_URL }}
|
||||||
|
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 }}
|
||||||
|
GH_TOKEN: ${{ secrets.GH_TOKEN }}
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
host:
|
host:
|
||||||
@@ -11,31 +33,14 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
submodules: recursive
|
||||||
|
token: ${{ secrets.GH_TOKEN }}
|
||||||
- uses: oven-sh/setup-bun@v1
|
- uses: oven-sh/setup-bun@v1
|
||||||
|
- uses: arduino/setup-protoc@v3
|
||||||
- name: Install dependencies
|
with:
|
||||||
run: bun install
|
repo-token: ${{ secrets.GH_TOKEN }}
|
||||||
|
- run: bun run setup
|
||||||
|
|
||||||
- name: Generate leaderboard
|
- name: Generate leaderboard
|
||||||
env:
|
|
||||||
PUBLIC_ASSET_BRANCH: main
|
|
||||||
PUBLIC_ASSET_REPO: ${{ secrets.PUBLIC_ASSET_REPO }}
|
|
||||||
DISCORD_CLIENT_ID: ${{ secrets.DISCORD_CLIENT_ID }}
|
|
||||||
GH_TOKEN: ${{ secrets.GH_TOKEN }}
|
|
||||||
DISCORD_TOKEN: ${{ secrets.DISCORD_TOKEN }}
|
|
||||||
DATABASE_URL: ${{ secrets.DATABASE_URL }}
|
|
||||||
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
|
||||||
@@ -3,7 +3,29 @@ name: Rating Europe
|
|||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
schedule:
|
schedule:
|
||||||
- cron: '0 23 * * *'
|
- cron: "0 23 * * *"
|
||||||
|
|
||||||
|
env:
|
||||||
|
PUBLIC_ASSET_BRANCH: main
|
||||||
|
PUBLIC_ASSET_REPO: ${{ secrets.PUBLIC_ASSET_REPO }}
|
||||||
|
DISCORD_CLIENT_ID: ${{ secrets.DISCORD_CLIENT_ID }}
|
||||||
|
DISCORD_TOKEN: ${{ secrets.DISCORD_TOKEN }}
|
||||||
|
DATABASE_URL: ${{ secrets.DATABASE_URL }}
|
||||||
|
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 }}
|
||||||
|
GH_TOKEN: ${{ secrets.GH_TOKEN }}
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
host:
|
host:
|
||||||
@@ -11,31 +33,14 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
submodules: recursive
|
||||||
|
token: ${{ secrets.GH_TOKEN }}
|
||||||
- uses: oven-sh/setup-bun@v1
|
- uses: oven-sh/setup-bun@v1
|
||||||
|
- uses: arduino/setup-protoc@v3
|
||||||
- name: Install dependencies
|
with:
|
||||||
run: bun install
|
repo-token: ${{ secrets.GH_TOKEN }}
|
||||||
|
- run: bun run setup
|
||||||
|
|
||||||
- name: Generate leaderboard
|
- name: Generate leaderboard
|
||||||
env:
|
|
||||||
PUBLIC_ASSET_BRANCH: main
|
|
||||||
PUBLIC_ASSET_REPO: ${{ secrets.PUBLIC_ASSET_REPO }}
|
|
||||||
DISCORD_CLIENT_ID: ${{ secrets.DISCORD_CLIENT_ID }}
|
|
||||||
GH_TOKEN: ${{ secrets.GH_TOKEN }}
|
|
||||||
DISCORD_TOKEN: ${{ secrets.DISCORD_TOKEN }}
|
|
||||||
DATABASE_URL: ${{ secrets.DATABASE_URL }}
|
|
||||||
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
|
||||||
@@ -3,7 +3,29 @@ name: Rating North America
|
|||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
schedule:
|
schedule:
|
||||||
- cron: '0 5 * * *'
|
- cron: "0 5 * * *"
|
||||||
|
|
||||||
|
env:
|
||||||
|
PUBLIC_ASSET_BRANCH: main
|
||||||
|
PUBLIC_ASSET_REPO: ${{ secrets.PUBLIC_ASSET_REPO }}
|
||||||
|
DISCORD_CLIENT_ID: ${{ secrets.DISCORD_CLIENT_ID }}
|
||||||
|
DISCORD_TOKEN: ${{ secrets.DISCORD_TOKEN }}
|
||||||
|
DATABASE_URL: ${{ secrets.DATABASE_URL }}
|
||||||
|
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 }}
|
||||||
|
GH_TOKEN: ${{ secrets.GH_TOKEN }}
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
host:
|
host:
|
||||||
@@ -11,31 +33,14 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
submodules: recursive
|
||||||
|
token: ${{ secrets.GH_TOKEN }}
|
||||||
- uses: oven-sh/setup-bun@v1
|
- uses: oven-sh/setup-bun@v1
|
||||||
|
- uses: arduino/setup-protoc@v3
|
||||||
- name: Install dependencies
|
with:
|
||||||
run: bun install
|
repo-token: ${{ secrets.GH_TOKEN }}
|
||||||
|
- run: bun run setup
|
||||||
|
|
||||||
- name: Generate leaderboard
|
- name: Generate leaderboard
|
||||||
env:
|
|
||||||
PUBLIC_ASSET_BRANCH: main
|
|
||||||
PUBLIC_ASSET_REPO: ${{ secrets.PUBLIC_ASSET_REPO }}
|
|
||||||
DISCORD_CLIENT_ID: ${{ secrets.DISCORD_CLIENT_ID }}
|
|
||||||
GH_TOKEN: ${{ secrets.GH_TOKEN }}
|
|
||||||
DISCORD_TOKEN: ${{ secrets.DISCORD_TOKEN }}
|
|
||||||
DATABASE_URL: ${{ secrets.DATABASE_URL }}
|
|
||||||
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
|
||||||
@@ -11,12 +11,13 @@ concurrency:
|
|||||||
|
|
||||||
env:
|
env:
|
||||||
DISCORD_TOKEN: ${{ secrets.DISCORD_TOKEN }}
|
DISCORD_TOKEN: ${{ secrets.DISCORD_TOKEN }}
|
||||||
GH_TOKEN: ${{ secrets.GH_TOKEN }}
|
|
||||||
DATABASE_URL: ${{ secrets.DATABASE_URL }}
|
DATABASE_URL: ${{ secrets.DATABASE_URL }}
|
||||||
PUBLIC_ASSET_BRANCH: ${{ secrets.PUBLIC_ASSET_BRANCH }}
|
PUBLIC_ASSET_BRANCH: ${{ secrets.PUBLIC_ASSET_BRANCH }}
|
||||||
PUBLIC_ASSET_REPO: ${{ secrets.PUBLIC_ASSET_REPO }}
|
PUBLIC_ASSET_REPO: ${{ secrets.PUBLIC_ASSET_REPO }}
|
||||||
GOOGLE_APPLICATION_CREDENTIALS: ${{ secrets.GOOGLE_APPLICATION_CREDENTIALS }}
|
GOOGLE_APPLICATION_CREDENTIALS: ${{ secrets.GOOGLE_APPLICATION_CREDENTIALS }}
|
||||||
PUBLIC_WARGAMING_APPLICATION_ID: ${{ secrets.PUBLIC_WARGAMING_APPLICATION_ID }}
|
PUBLIC_WARGAMING_APPLICATION_ID: ${{ secrets.PUBLIC_WARGAMING_APPLICATION_ID }}
|
||||||
|
GH_TOKEN: ${{ secrets.GH_TOKEN }}
|
||||||
|
PUBLIC_ASSET_BASE: ${{ secrets.PUBLIC_ASSET_BASE }}
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
@@ -27,11 +28,11 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
submodules: recursive
|
submodules: recursive
|
||||||
token: ${{ secrets.GH_TOKEN }}
|
token: ${{ secrets.GH_TOKEN }}
|
||||||
|
|
||||||
- uses: oven-sh/setup-bun@v1
|
- uses: oven-sh/setup-bun@v1
|
||||||
|
- uses: arduino/setup-protoc@v3
|
||||||
- name: Install dependencies
|
with:
|
||||||
run: bun install
|
repo-token: ${{ secrets.GH_TOKEN }}
|
||||||
|
- run: bun run setup
|
||||||
|
|
||||||
- name: Find reviews
|
- name: Find reviews
|
||||||
run: bun packages/scripts/src/reviews.ts
|
run: bun run build:reviews
|
||||||
@@ -5,7 +5,7 @@ on:
|
|||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
schedule:
|
schedule:
|
||||||
- cron: '0 4 * * *'
|
- cron: "0 4 * * *"
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: read
|
||||||
@@ -31,6 +31,7 @@ env:
|
|||||||
PUBLIC_BRANCH: ${{ secrets.PUBLIC_BRANCH }}
|
PUBLIC_BRANCH: ${{ secrets.PUBLIC_BRANCH }}
|
||||||
PUBLIC_GUIDE_WEBSITE: ${{ secrets.PUBLIC_GUIDE_WEBSITE }}
|
PUBLIC_GUIDE_WEBSITE: ${{ secrets.PUBLIC_GUIDE_WEBSITE }}
|
||||||
SERVICING: ${{ secrets.SERVICING }}
|
SERVICING: ${{ secrets.SERVICING }}
|
||||||
|
GH_TOKEN: ${{ secrets.GH_TOKEN }}
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
@@ -41,12 +42,12 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
submodules: recursive
|
submodules: recursive
|
||||||
token: ${{ secrets.GH_TOKEN }}
|
token: ${{ secrets.GH_TOKEN }}
|
||||||
|
|
||||||
- uses: oven-sh/setup-bun@v1
|
- uses: oven-sh/setup-bun@v1
|
||||||
|
- uses: arduino/setup-protoc@v3
|
||||||
|
with:
|
||||||
|
repo-token: ${{ secrets.GH_TOKEN }}
|
||||||
- uses: actions/configure-pages@v5
|
- uses: actions/configure-pages@v5
|
||||||
|
- run: bun run setup
|
||||||
- name: Install dependencies
|
|
||||||
run: bun install
|
|
||||||
|
|
||||||
- name: Build website
|
- name: Build website
|
||||||
run: bun run build:website
|
run: bun run build:website
|
||||||
|
|||||||
+25
-1
@@ -28,4 +28,28 @@ target
|
|||||||
.vercel
|
.vercel
|
||||||
/src
|
/src
|
||||||
/packages/bot/src/prisma
|
/packages/bot/src/prisma
|
||||||
dev-dist
|
dev-dist
|
||||||
|
# Logs
|
||||||
|
logs
|
||||||
|
*.log
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
pnpm-debug.log*
|
||||||
|
lerna-debug.log*
|
||||||
|
|
||||||
|
node_modules
|
||||||
|
dist
|
||||||
|
dist-ssr
|
||||||
|
*.local
|
||||||
|
|
||||||
|
# Editor directories and files
|
||||||
|
.vscode/*
|
||||||
|
!.vscode/extensions.json
|
||||||
|
.idea
|
||||||
|
.DS_Store
|
||||||
|
*.suo
|
||||||
|
*.ntvs*
|
||||||
|
*.njsproj
|
||||||
|
*.sln
|
||||||
|
*.sw?
|
||||||
+3
-9
@@ -1,9 +1,3 @@
|
|||||||
[submodule "submodules/blitzkit-closed"]
|
[submodule "packages/closed"]
|
||||||
path = submodules/blitzkit-closed
|
path = packages/closed
|
||||||
url = https://github.com/tresabhi/blitzkit-closed
|
url = https://github.com/blitzkit/closed.git
|
||||||
[submodule "submodules/CUE4Parse"]
|
|
||||||
path = submodules/CUE4Parse
|
|
||||||
url = https://github.com/FabianFG/CUE4Parse
|
|
||||||
[submodule "submodules/blitzkit-internal"]
|
|
||||||
path = submodules/blitzkit-internal
|
|
||||||
url = https://github.com/blitzkit/internal
|
|
||||||
Vendored
+18
@@ -11,6 +11,7 @@
|
|||||||
"analyticsreporting",
|
"analyticsreporting",
|
||||||
"APAC",
|
"APAC",
|
||||||
"apcr",
|
"apcr",
|
||||||
|
"appinfo",
|
||||||
"applypatches",
|
"applypatches",
|
||||||
"artefacts",
|
"artefacts",
|
||||||
"astrojs",
|
"astrojs",
|
||||||
@@ -34,12 +35,14 @@
|
|||||||
"blitzkit",
|
"blitzkit",
|
||||||
"blitzrinth",
|
"blitzrinth",
|
||||||
"blitzstars",
|
"blitzstars",
|
||||||
|
"bufbuild",
|
||||||
"cacheable",
|
"cacheable",
|
||||||
"Callouts",
|
"Callouts",
|
||||||
"Camo",
|
"Camo",
|
||||||
"Carro",
|
"Carro",
|
||||||
"CCPAOPTOUT",
|
"CCPAOPTOUT",
|
||||||
"CDON",
|
"CDON",
|
||||||
|
"clanid",
|
||||||
"classname",
|
"classname",
|
||||||
"cleandist",
|
"cleandist",
|
||||||
"closedkrieg",
|
"closedkrieg",
|
||||||
@@ -62,8 +65,10 @@
|
|||||||
"deburr",
|
"deburr",
|
||||||
"decalmask",
|
"decalmask",
|
||||||
"decompressor",
|
"decompressor",
|
||||||
|
"dedup",
|
||||||
"defence",
|
"defence",
|
||||||
"degressive",
|
"degressive",
|
||||||
|
"depotdownloader",
|
||||||
"devkrieg",
|
"devkrieg",
|
||||||
"diacriticless",
|
"diacriticless",
|
||||||
"DIDS",
|
"DIDS",
|
||||||
@@ -74,6 +79,7 @@
|
|||||||
"DVPLCRC",
|
"DVPLCRC",
|
||||||
"dvpm",
|
"dvpm",
|
||||||
"dxgi",
|
"dxgi",
|
||||||
|
"easimon",
|
||||||
"echarts",
|
"echarts",
|
||||||
"Everytime",
|
"Everytime",
|
||||||
"FASTNAME",
|
"FASTNAME",
|
||||||
@@ -86,11 +92,13 @@
|
|||||||
"Fullscreen",
|
"Fullscreen",
|
||||||
"fullstats",
|
"fullstats",
|
||||||
"fuzzysort",
|
"fuzzysort",
|
||||||
|
"gamemode",
|
||||||
"gameplay",
|
"gameplay",
|
||||||
"glsl",
|
"glsl",
|
||||||
"GLTF",
|
"GLTF",
|
||||||
"gtag",
|
"gtag",
|
||||||
"haha",
|
"haha",
|
||||||
|
"Herdbreaker",
|
||||||
"highp",
|
"highp",
|
||||||
"iife",
|
"iife",
|
||||||
"imgur",
|
"imgur",
|
||||||
@@ -104,6 +112,7 @@
|
|||||||
"leaderboards",
|
"leaderboards",
|
||||||
"lerp",
|
"lerp",
|
||||||
"LINEARSIZE",
|
"LINEARSIZE",
|
||||||
|
"linktarget",
|
||||||
"lmao",
|
"lmao",
|
||||||
"loadouts",
|
"loadouts",
|
||||||
"loddist",
|
"loddist",
|
||||||
@@ -126,6 +135,7 @@
|
|||||||
"NEGATIVEX",
|
"NEGATIVEX",
|
||||||
"NEGATIVEY",
|
"NEGATIVEY",
|
||||||
"NEGATIVEZ",
|
"NEGATIVEZ",
|
||||||
|
"networkidle",
|
||||||
"NITROPAY",
|
"NITROPAY",
|
||||||
"nivo",
|
"nivo",
|
||||||
"nmatname",
|
"nmatname",
|
||||||
@@ -136,11 +146,13 @@
|
|||||||
"Oopsy",
|
"Oopsy",
|
||||||
"opentest",
|
"opentest",
|
||||||
"OPTML",
|
"OPTML",
|
||||||
|
"otemp",
|
||||||
"outdir",
|
"outdir",
|
||||||
"outfile",
|
"outfile",
|
||||||
"ownedtanks",
|
"ownedtanks",
|
||||||
"padder",
|
"padder",
|
||||||
"partytown",
|
"partytown",
|
||||||
|
"patchnotes",
|
||||||
"PIXELFORMAT",
|
"PIXELFORMAT",
|
||||||
"playerachievements",
|
"playerachievements",
|
||||||
"playerinfo",
|
"playerinfo",
|
||||||
@@ -153,11 +165,15 @@
|
|||||||
"Promisable",
|
"Promisable",
|
||||||
"proto",
|
"proto",
|
||||||
"protobuf",
|
"protobuf",
|
||||||
|
"protoc",
|
||||||
"protos",
|
"protos",
|
||||||
|
"proxyclient",
|
||||||
|
"prunestrings",
|
||||||
"Pyogenics",
|
"Pyogenics",
|
||||||
"ratingleaderboard",
|
"ratingleaderboard",
|
||||||
"raycaster",
|
"raycaster",
|
||||||
"Redirector",
|
"Redirector",
|
||||||
|
"Relogin",
|
||||||
"researchable",
|
"researchable",
|
||||||
"Resvg",
|
"Resvg",
|
||||||
"rizz",
|
"rizz",
|
||||||
@@ -206,12 +222,14 @@
|
|||||||
"Unregistering",
|
"Unregistering",
|
||||||
"unrotate",
|
"unrotate",
|
||||||
"unwrapper",
|
"unwrapper",
|
||||||
|
"userns",
|
||||||
"vercel",
|
"vercel",
|
||||||
"vickers",
|
"vickers",
|
||||||
"vitepress",
|
"vitepress",
|
||||||
"Vovko",
|
"Vovko",
|
||||||
"wargaming",
|
"wargaming",
|
||||||
"webp",
|
"webp",
|
||||||
|
"wgpkg",
|
||||||
"whitespaces",
|
"whitespaces",
|
||||||
"WHSS",
|
"WHSS",
|
||||||
"winrate",
|
"winrate",
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
# BlitzKit
|
# BlitzKit
|
||||||
|
|
||||||
Tools for everything and anything World of Tanks Blitz.
|
Tools for everything and anything, World of Tanks Blitz.
|
||||||
|
|
||||||
This GitHub repository contains the code for BlitzKit and all its services. You may need to checkout sensitive closed-source submodules in order to locally develop some aspects of BlitzKit. Communicate with `@tresabhi` on Discord to get started or talk about sensitive content like environment variables or submodules.
|
This GitHub repository contains the code for BlitzKit and all its services. If you are here, looking to use BlitzKit, go to https://blitzkit.app/.
|
||||||
|
|
||||||
|
If you intend to contribute to the code, note that you may need to check out sensitive, closed-source submodules to locally develop certain aspects of BlitzKit. Communicate with `@tresabhi` on Discord to get started or discuss sensitive content, such as environment variables or submodules.
|
||||||
|
|
||||||
## Packages
|
## Packages
|
||||||
|
|
||||||
@@ -13,23 +15,21 @@ This GitHub repository contains the code for BlitzKit and all its services. You
|
|||||||
| [packages/core](packages/core) | | | Mutual internal code shared between all other packages. |
|
| [packages/core](packages/core) | | | Mutual internal code shared between all other packages. |
|
||||||
| [packages/i18n](packages/i18n) | | [Crowdin](https://crowdin.com/project/blitzkrieg) | Translations served as JSON shared across all other packages, including some utility code. |
|
| [packages/i18n](packages/i18n) | | [Crowdin](https://crowdin.com/project/blitzkrieg) | Translations served as JSON shared across all other packages, including some utility code. |
|
||||||
| [packages/scripts](packages/scripts) | | | CLI utilities for the development and deployment of BlitzKit services. |
|
| [packages/scripts](packages/scripts) | | | CLI utilities for the development and deployment of BlitzKit services. |
|
||||||
| [packages/varuna](packages/varuna) | Varuna | [NPM](https://www.npmjs.com/package/varuna) | React and Astro oriented state management library, awaiting separation from BlitzKit. Unavailable from NPM at this time. |
|
| [packages/varuna](packages/varuna) | Varuna | [NPM](https://www.npmjs.com/package/varuna) | React and Astro-oriented state management library, awaiting separation from BlitzKit. Unavailable from NPM at this time. |
|
||||||
| [packages/website](packages/website) | BlitzKit | https://blitzkit.app | The BlitzKit website providing a wide range of tools, APIs, and interconnecting all other services. |
|
| [packages/website](packages/website) | BlitzKit | https://blitzkit.app | The BlitzKit website provides a wide range of tools, APIs, and interconnects all other services. |
|
||||||
|
|
||||||
## Submodules
|
## Submodules
|
||||||
|
|
||||||
| Submodule | Title | Source | Memo |
|
| Submodule | Title | Source | Memo |
|
||||||
| ------------------------------------------------------------ | ----------- | ----------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
| ------------------------------------------------------ | --------- | ----------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||||
| [submodules/blitzkit-closed](submodules/blitzkit-closed) | ClosedKit | [blitzkit/closed](https://github.com/blitzkit/closed) | Closed source, sensitive code hidden from the public to prevent bad actors from abusing the game. Discuss with `@tresabhi` on Discord for **special permission** to access. |
|
| [submodules/blitzkit-closed](packages/blitzkit-closed) | ClosedKit | [blitzkit/closed](https://github.com/blitzkit/closed) | Closed source, sensitive code hidden from the public to prevent bad actors from abusing the game. Discuss with `@tresabhi` on Discord for **special permission** to access. |
|
||||||
| [submodules/blitzkit-internal](submodules/blitzkit-internal) | InternalKit | [blitzkit/internal](https://github.com/blitzkit/internal) | Closed source, sensitive internal documentation hidden from the public to prevent bad actors from abusing the game. Access to this submodule is **not negotiable**. |
|
|
||||||
| [submodules/CUE4Parse](submodules/CUE4Parse) | CUE4Parse | [FabianFG/CUE4Parse](https://github.com/FabianFG/CUE4Parse) | An Unreal Engine archives and packages parsing library in C#. |
|
|
||||||
|
|
||||||
## Environment Variables
|
## Environment Variables
|
||||||
|
|
||||||
| Name | Source | BlitzKit Default | Memo |
|
| Name | Source | BlitzKit Default | Memo |
|
||||||
| ------------------------------------------------------------- | -------------------------------------------------------------------------------- | ----------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
|
| ------------------------------------------------------------- | -------------------------------------------------------------------------------- | ----------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
|
||||||
| `PUBLIC_WARGAMING_APPLICATION_ID` | [Wargaming Developer's Room](https://developers.wargaming.net/) | | Application ID needed to communicate with Wargaming APIs. |
|
| `PUBLIC_WARGAMING_APPLICATION_ID` | [Wargaming Developer's Room](https://developers.wargaming.net/) | | Application ID needed to communicate with Wargaming APIs. |
|
||||||
| `PUBLIC_PROMOTE_OPENTEST` | | `false` | Optional boolean dictating wether the website advertises [the opentest subdomain of BlitzKit](https://opentest.blitzkit.app/). |
|
| `PUBLIC_PROMOTE_OPENTEST` | | `false` | Optional boolean dictating whether the website advertises [the opentest subdomain of BlitzKit](https://opentest.blitzkit.app/). |
|
||||||
| `ALLOW_ROBOTS` | | `true` | Toggles between `Allow: /` and `Disallow: /` in the website's `/robots.txt`. This is usually `false` for all BlitzKit's subdomains. |
|
| `ALLOW_ROBOTS` | | `true` | Toggles between `Allow: /` and `Disallow: /` in the website's `/robots.txt`. This is usually `false` for all BlitzKit's subdomains. |
|
||||||
| `WOTB_GLOSSARY`, `WOTB_GLOSSARY_DOMAIN`, `WOTB_GLOSSARY_PATH` | | | |
|
| `WOTB_GLOSSARY`, `WOTB_GLOSSARY_DOMAIN`, `WOTB_GLOSSARY_PATH` | | | |
|
||||||
| `PUBLIC_GOOGLE_TAG_MANAGER_ID` | [Google Tag Manager](https://tagmanager.google.com/) | `G-GL2JVHCGPQ` | Google Tag Manager's unique identifier for analytical purposes. |
|
| `PUBLIC_GOOGLE_TAG_MANAGER_ID` | [Google Tag Manager](https://tagmanager.google.com/) | `G-GL2JVHCGPQ` | Google Tag Manager's unique identifier for analytical purposes. |
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
# BlitzKit 1.28.2
|
||||||
|
|
||||||
|
## Fixes
|
||||||
|
|
||||||
|
- BlitzKit no longer tries to redirect translated pages to the same page, over and over again
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
# BlitzKit 1.28.3
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- Turrets and guns can now be rotated in Mixer without any pitch or yaw limits
|
||||||
|
- Added nation icons to the search results for Guesser
|
||||||
|
- The table now occupies the whole screen in Compare
|
||||||
|
- Added the ability to log in with a Wargaming account in the navbar
|
||||||
|
- Added owned/unowned filters in the Tankopedia filters
|
||||||
|
- Revamped Tankopedia quick controls to be more accessible and obvious
|
||||||
|
|
||||||
|
## Fixes
|
||||||
|
|
||||||
|
- Missing tank icons across the website have been fixed
|
||||||
|
- Events of starting and stopping of the transform tanks now use an asynchronous event instead of a reactive state, making them faster
|
||||||
|
- Removed a hook call on root context, speeding up load times
|
||||||
|
- Tankopedia's pitch input now follows the same sign convention as the pitch and yaw visualizer
|
||||||
|
- Shadows are no longer disabled when the scene is unloaded when the user scrolls away from the canvas
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
# BlitzKit 1.28.4
|
||||||
|
|
||||||
|
## Fixes
|
||||||
|
|
||||||
|
- The tank names in the Tankopedia sandbox now have less margin from the navbar
|
||||||
|
- Controls in the Tankopedia sandbox are now shown in all modes, except for the advanced highlighting button which only appears in the dynamic armor mode
|
||||||
|
- The settings page now reacts to input again
|
||||||
|
- The settings page now has a tab title and description for search engines
|
||||||
|
- Added support for transparent textures, fixing tanks like the Herdbreaker and the WZ-132-1
|
||||||
|
- The tank filters in the Performance and Tier-List tools work once again
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
# BlitzKit 1.29.0
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- Added the Playlist tool
|
||||||
|
- Don't know what to play today? Let BlitzKit do the thinking!
|
||||||
|
- Navigate to [the tool on BlitzKit](https://blitzkit.app/playlist)
|
||||||
|
- Make sure you login with your Wargaming account to unlock all features like live tracking and filtering by owned tanks
|
||||||
|
- Use filters to pick tiers, nations, etc. then hit Generate playlist
|
||||||
|
- BlitzKit will generate a checklist for you to go through as you play
|
||||||
|
- Don't like the order of tanks? Hit Shuffle, Sort by Last played and Least played, or straight up remove tanks from the list by using the (-) button
|
||||||
|
- If you're logged in, BlitzKit will automatically check off tanks as you play them
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
# BlitzKit 1.29.1
|
||||||
|
|
||||||
|
## Technical Changes
|
||||||
|
|
||||||
|
- Recreated the full dependency tree for BlitzKit
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
# BlitzKit 1.29.2
|
||||||
|
|
||||||
|
## Technical Changes
|
||||||
|
|
||||||
|
- Implemented new workflow capabilities to deploy BlitzKit OpenTest and Preview remotely, from any device
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
# BlitzKit 1.29.3
|
||||||
|
|
||||||
|
## Technical Changes
|
||||||
|
|
||||||
|
- Added a significantly more memory and network efficient AssetUploader abstraction
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
# BlitzKit 1.29.4
|
||||||
|
|
||||||
|
## Technical Changes
|
||||||
|
|
||||||
|
- BlitzKit now partially downloads game files instead of the entire game, allowing for faster updates
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
# BlitzKit 1.29.5
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- Added new lighting to be a bit softer on tanks
|
||||||
|
- Added a button with the sun icon to toggle high graphics
|
||||||
|
- Added a new reveal and transition animation between tabs
|
||||||
|
|
||||||
|
## Fixes
|
||||||
|
|
||||||
|
- Track wheels on some tanks no longer look translucent
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
# BlitzKit 1.29.6
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- Simplified the ownership and test tank filters in the tank search
|
||||||
|
- Renamed "Guess the tank" to simply "Guess"
|
||||||
|
- The player count value in the Performance tool is now set to Total by default
|
||||||
|
- Added Compare-like red/green highlighting to the Performance tool
|
||||||
|
|
||||||
|
## Changes
|
||||||
|
|
||||||
|
- Removed the last updated info bar in Performance for some more screen real estate
|
||||||
|
|
||||||
|
## Fixes
|
||||||
|
|
||||||
|
- The remove played tanks in the Playlist tool now shows even when logged out
|
||||||
|
- The Guess game now has a page title
|
||||||
|
- The compare table now occupies the minimum width possible instead of expanding all columns excessively
|
||||||
+16
-30
@@ -1,23 +1,18 @@
|
|||||||
{
|
{
|
||||||
"name": "blitzkit",
|
"name": "blitzkit",
|
||||||
|
"version": "1.29.6",
|
||||||
|
"license": "BlitzKit License",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "1.28.1",
|
|
||||||
"description": "🎉 Tools for everything World of Tanks Blitz",
|
|
||||||
"type": "module",
|
|
||||||
"types": "./types.d.ts",
|
|
||||||
"workspaces": [
|
|
||||||
"packages/*"
|
|
||||||
],
|
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build:assets": "cd packages/scripts && bun run build:assets",
|
"build:assets": "cd packages/scripts && bun run build:assets",
|
||||||
"build:averages": "bun --filter=@blitzkit/scripts run build:averages",
|
"build:averages": "bun --filter=@blitzkit/scripts run build:averages",
|
||||||
"build:bot": "cd packages/scripts && bun run build:bot",
|
"build:bot": "cd packages/scripts && bun run build:bot",
|
||||||
"build:website": "bun build:prisma --no-hints && cd packages/website && bun run build",
|
"build:website": "cd packages/website && bun run build",
|
||||||
"build:prisma": "prisma generate",
|
"build:prisma": "prisma generate",
|
||||||
"build:sitemap": "bun scripts/sitemap.ts",
|
|
||||||
"build:docs": "vitepress build docs",
|
|
||||||
"build:proxyclient": "cd packages/scripts && bun run build:proxyclient",
|
"build:proxyclient": "cd packages/scripts && bun run build:proxyclient",
|
||||||
|
"build:catalogitemaccesssor": "cd packages/scripts && bun run build:catalogitemaccesssor",
|
||||||
"build:ratingleaderboard": "cd packages/scripts && bun run build:ratingleaderboard",
|
"build:ratingleaderboard": "cd packages/scripts && bun run build:ratingleaderboard",
|
||||||
|
"build:app": "cd packages/app && bun run build",
|
||||||
"dev:bot": "bun run build:bot --dev && bun start:bot",
|
"dev:bot": "bun run build:bot --dev && bun start:bot",
|
||||||
"start:bot": "bun dist/bot/main.js",
|
"start:bot": "bun dist/bot/main.js",
|
||||||
"dev:docs": "vitepress dev docs",
|
"dev:docs": "vitepress dev docs",
|
||||||
@@ -35,30 +30,21 @@
|
|||||||
"update": "yarn upgrade --latest",
|
"update": "yarn upgrade --latest",
|
||||||
"tunnel": "cloudflared tunnel --url http://localhost:3000",
|
"tunnel": "cloudflared tunnel --url http://localhost:3000",
|
||||||
"discoverids": "scripts/discoverIds.ts",
|
"discoverids": "scripts/discoverIds.ts",
|
||||||
"build:protos": "bun packages/scripts/src/protos.ts",
|
"build:protos": "cd packages/scripts && bun run build:protos",
|
||||||
"preview:website": "cd packages/website && bun run preview",
|
"preview:website": "cd packages/website && bun run preview",
|
||||||
"build:reviews": "cd packages/scripts && bun build:reviews",
|
"build:reviews": "cd packages/scripts && bun build:reviews",
|
||||||
"build:ids": "cd packages/scripts && bun build:ids",
|
"build:ids": "cd packages/scripts && bun build:ids",
|
||||||
"prunestrings": "cd packages/scripts && bun prunestrings"
|
"prunestrings": "cd packages/scripts && bun prunestrings",
|
||||||
|
"setup": "bun install && bun run build:prisma && bun run build:protos && bun run build:proxyclient",
|
||||||
|
"patchnotes": "cd packages/scripts && bun run patchnotes"
|
||||||
},
|
},
|
||||||
"license": "MIT",
|
"type": "module",
|
||||||
|
"workspaces": [
|
||||||
|
"packages/*"
|
||||||
|
],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/xmpp__client": "^0.13.3",
|
"@prisma/client": "^6.18.0",
|
||||||
"@xmpp/client": "^0.13.6",
|
"prisma": "^6.18.0",
|
||||||
"astro-favicons": "^3.1.5",
|
"typescript": "^5.9.3"
|
||||||
"cheerio": "^1.1.2",
|
|
||||||
"googleapis": "^160.0.0",
|
|
||||||
"lodash-es": "^4.17.21",
|
|
||||||
"protobufjs": "^7.5.4",
|
|
||||||
"quicklime": "^1.2.0",
|
|
||||||
"sharp": "^0.34.4"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"@types/bun": "^1.2.22",
|
|
||||||
"@types/lodash-es": "^4.17.12",
|
|
||||||
"@types/node": "^24.5.2",
|
|
||||||
"prettier": "^3.6.2",
|
|
||||||
"prisma": "^6.16.2",
|
|
||||||
"typescript": "^5.9.2"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
# Logs
|
|
||||||
logs
|
|
||||||
*.log
|
|
||||||
npm-debug.log*
|
|
||||||
yarn-debug.log*
|
|
||||||
yarn-error.log*
|
|
||||||
pnpm-debug.log*
|
|
||||||
lerna-debug.log*
|
|
||||||
|
|
||||||
node_modules
|
|
||||||
dist
|
|
||||||
dist-ssr
|
|
||||||
*.local
|
|
||||||
|
|
||||||
# Editor directories and files
|
|
||||||
.vscode/*
|
|
||||||
!.vscode/extensions.json
|
|
||||||
.idea
|
|
||||||
.DS_Store
|
|
||||||
*.suo
|
|
||||||
*.ntvs*
|
|
||||||
*.njsproj
|
|
||||||
*.sln
|
|
||||||
*.sw?
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
<!doctype html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8" />
|
|
||||||
<link rel="stylesheet" href="/src/styles.css" />
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
||||||
<title>Tauri App</title>
|
|
||||||
<script type="module" src="/src/main.ts" defer></script>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
<main class="container">
|
|
||||||
<h1>Welcome to Tauri</h1>
|
|
||||||
|
|
||||||
<div class="row">
|
|
||||||
<a href="https://vite.dev" target="_blank">
|
|
||||||
<img src="/src/assets/vite.svg" class="logo vite" alt="Vite logo" />
|
|
||||||
</a>
|
|
||||||
<a href="https://tauri.app" target="_blank">
|
|
||||||
<img
|
|
||||||
src="/src/assets/tauri.svg"
|
|
||||||
class="logo tauri"
|
|
||||||
alt="Tauri logo"
|
|
||||||
/>
|
|
||||||
</a>
|
|
||||||
<a href="https://www.typescriptlang.org/docs" target="_blank">
|
|
||||||
<img
|
|
||||||
src="/src/assets/typescript.svg"
|
|
||||||
class="logo typescript"
|
|
||||||
alt="typescript logo"
|
|
||||||
/>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
<p>Click on the Tauri logo to learn more about the framework</p>
|
|
||||||
|
|
||||||
<form class="row" id="greet-form">
|
|
||||||
<input id="greet-input" placeholder="Enter a name..." />
|
|
||||||
<button type="submit">Greet</button>
|
|
||||||
</form>
|
|
||||||
<p id="greet-msg"></p>
|
|
||||||
</main>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
Generated
+5286
File diff suppressed because it is too large.
Load diff
@@ -1,6 +1,27 @@
|
|||||||
// Prevents additional console window on Windows in release, DO NOT REMOVE!!
|
|
||||||
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
|
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
|
||||||
|
|
||||||
|
use std::process::{Command, Stdio};
|
||||||
|
use tauri::Manager;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
blitzkit_lib::run()
|
tauri::Builder::default()
|
||||||
|
.setup(|app| {
|
||||||
|
let app_handle = app.handle();
|
||||||
|
|
||||||
|
let entry = app_handle
|
||||||
|
.path_resolver()
|
||||||
|
.resolve_resource("../../dist/website/server/entry.mjs")
|
||||||
|
.expect("failed to resolve server.ts");
|
||||||
|
|
||||||
|
Command::new("bun")
|
||||||
|
.arg("run")
|
||||||
|
.arg(entry)
|
||||||
|
.stderr(Stdio::null())
|
||||||
|
.spawn()
|
||||||
|
.expect("failed to start Bun server");
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
})
|
||||||
|
.run(tauri::generate_context!())
|
||||||
|
.expect("error while running Tauri app");
|
||||||
}
|
}
|
||||||
@@ -4,18 +4,20 @@
|
|||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"identifier": "com.tresabhi.blitzkit",
|
"identifier": "com.tresabhi.blitzkit",
|
||||||
"build": {
|
"build": {
|
||||||
"beforeDevCommand": "bun run dev",
|
"beforeDevCommand": "cd ../website && bun run dev",
|
||||||
"devUrl": "http://localhost:1420",
|
"_beforeBuildCommand": "cd ../website && bun run build",
|
||||||
"beforeBuildCommand": "bun run build",
|
"frontendDist": "../../../dist/website/client",
|
||||||
"frontendDist": "../dist"
|
"devUrl": "http://localhost:4321"
|
||||||
},
|
},
|
||||||
"app": {
|
"app": {
|
||||||
"withGlobalTauri": true,
|
"withGlobalTauri": true,
|
||||||
"windows": [
|
"windows": [
|
||||||
{
|
{
|
||||||
"title": "blitzkit",
|
"url": "http://localhost:4321",
|
||||||
"width": 800,
|
"title": "BlitzKit",
|
||||||
"height": 600
|
"fullscreen": false,
|
||||||
|
"resizable": true,
|
||||||
|
"maximized": true
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"security": {
|
"security": {
|
||||||
|
|||||||
@@ -1,6 +0,0 @@
|
|||||||
<svg width="206" height="231" viewBox="0 0 206 231" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
||||||
<path d="M143.143 84C143.143 96.1503 133.293 106 121.143 106C108.992 106 99.1426 96.1503 99.1426 84C99.1426 71.8497 108.992 62 121.143 62C133.293 62 143.143 71.8497 143.143 84Z" fill="#FFC131"/>
|
|
||||||
<ellipse cx="84.1426" cy="147" rx="22" ry="22" transform="rotate(180 84.1426 147)" fill="#24C8DB"/>
|
|
||||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M166.738 154.548C157.86 160.286 148.023 164.269 137.757 166.341C139.858 160.282 141 153.774 141 147C141 144.543 140.85 142.121 140.558 139.743C144.975 138.204 149.215 136.139 153.183 133.575C162.73 127.404 170.292 118.608 174.961 108.244C179.63 97.8797 181.207 86.3876 179.502 75.1487C177.798 63.9098 172.884 53.4021 165.352 44.8883C157.82 36.3744 147.99 30.2165 137.042 27.1546C126.095 24.0926 114.496 24.2568 103.64 27.6274C92.7839 30.998 83.1319 37.4317 75.8437 46.1553C74.9102 47.2727 74.0206 48.4216 73.176 49.5993C61.9292 50.8488 51.0363 54.0318 40.9629 58.9556C44.2417 48.4586 49.5653 38.6591 56.679 30.1442C67.0505 17.7298 80.7861 8.57426 96.2354 3.77762C111.685 -1.01901 128.19 -1.25267 143.769 3.10474C159.348 7.46215 173.337 16.2252 184.056 28.3411C194.775 40.457 201.767 55.4101 204.193 71.404C206.619 87.3978 204.374 103.752 197.73 118.501C191.086 133.25 180.324 145.767 166.738 154.548ZM41.9631 74.275L62.5557 76.8042C63.0459 72.813 63.9401 68.9018 65.2138 65.1274C57.0465 67.0016 49.2088 70.087 41.9631 74.275Z" fill="#FFC131"/>
|
|
||||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M38.4045 76.4519C47.3493 70.6709 57.2677 66.6712 67.6171 64.6132C65.2774 70.9669 64 77.8343 64 85.0001C64 87.1434 64.1143 89.26 64.3371 91.3442C60.0093 92.8732 55.8533 94.9092 51.9599 97.4256C42.4128 103.596 34.8505 112.392 30.1816 122.756C25.5126 133.12 23.9357 144.612 25.6403 155.851C27.3449 167.09 32.2584 177.598 39.7906 186.112C47.3227 194.626 57.153 200.784 68.1003 203.846C79.0476 206.907 90.6462 206.743 101.502 203.373C112.359 200.002 122.011 193.568 129.299 184.845C130.237 183.722 131.131 182.567 131.979 181.383C143.235 180.114 154.132 176.91 164.205 171.962C160.929 182.49 155.596 192.319 148.464 200.856C138.092 213.27 124.357 222.426 108.907 227.222C93.458 232.019 76.9524 232.253 61.3736 227.895C45.7948 223.538 31.8055 214.775 21.0867 202.659C10.3679 190.543 3.37557 175.59 0.949823 159.596C-1.47592 143.602 0.768139 127.248 7.41237 112.499C14.0566 97.7497 24.8183 85.2327 38.4045 76.4519ZM163.062 156.711L163.062 156.711C162.954 156.773 162.846 156.835 162.738 156.897C162.846 156.835 162.954 156.773 163.062 156.711Z" fill="#24C8DB"/>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 2.5 KiB |
@@ -1,25 +0,0 @@
|
|||||||
<?xml version="1.0" standalone="no"?>
|
|
||||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
|
|
||||||
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
|
|
||||||
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
|
|
||||||
width="512.000000pt" height="512.000000pt" viewBox="0 0 512.000000 512.000000"
|
|
||||||
preserveAspectRatio="xMidYMid meet">
|
|
||||||
|
|
||||||
<g transform="translate(0.000000,512.000000) scale(0.100000,-0.100000)"
|
|
||||||
fill="#2D79C7" stroke="none">
|
|
||||||
<path d="M430 5109 c-130 -19 -248 -88 -325 -191 -53 -71 -83 -147 -96 -247
|
|
||||||
-6 -49 -9 -813 -7 -2166 l3 -2090 22 -65 c54 -159 170 -273 328 -323 l70 -22
|
|
||||||
2140 0 2140 0 66 23 c160 55 272 169 322 327 l22 70 0 2135 0 2135 -22 70
|
|
||||||
c-49 157 -155 265 -319 327 l-59 23 -2115 1 c-1163 1 -2140 -2 -2170 -7z
|
|
||||||
m3931 -2383 c48 -9 120 -26 160 -39 l74 -23 3 -237 c1 -130 0 -237 -2 -237 -3
|
|
||||||
0 -26 14 -53 30 -61 38 -197 84 -310 106 -110 20 -293 15 -368 -12 -111 -39
|
|
||||||
-175 -110 -175 -193 0 -110 97 -197 335 -300 140 -61 309 -146 375 -189 30
|
|
||||||
-20 87 -68 126 -107 119 -117 164 -234 164 -426 0 -310 -145 -518 -430 -613
|
|
||||||
-131 -43 -248 -59 -445 -60 -243 -1 -405 24 -577 90 l-68 26 0 242 c0 175 -3
|
|
||||||
245 -12 254 -9 9 -9 12 0 12 7 0 12 -4 12 -9 0 -17 139 -102 223 -138 136 -57
|
|
||||||
233 -77 382 -76 145 0 224 19 295 68 75 52 100 156 59 242 -41 84 -135 148
|
|
||||||
-374 253 -367 161 -522 300 -581 520 -23 86 -23 253 -1 337 73 275 312 448
|
|
||||||
682 492 109 13 401 6 506 -13z m-1391 -241 l0 -205 -320 0 -320 0 0 -915 0
|
|
||||||
-915 -255 0 -255 0 0 915 0 915 -320 0 -320 0 0 205 0 205 895 0 895 0 0 -205z"/>
|
|
||||||
</g>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 1.4 KiB |
@@ -1 +0,0 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
|
|
||||||
|
Before Width: | Height: | Size: 1.5 KiB |
@@ -1,22 +0,0 @@
|
|||||||
import { invoke } from "@tauri-apps/api/core";
|
|
||||||
|
|
||||||
let greetInputEl: HTMLInputElement | null;
|
|
||||||
let greetMsgEl: HTMLElement | null;
|
|
||||||
|
|
||||||
async function greet() {
|
|
||||||
if (greetMsgEl && greetInputEl) {
|
|
||||||
// Learn more about Tauri commands at https://tauri.app/develop/calling-rust/
|
|
||||||
greetMsgEl.textContent = await invoke("greet", {
|
|
||||||
name: greetInputEl.value,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
window.addEventListener("DOMContentLoaded", () => {
|
|
||||||
greetInputEl = document.querySelector("#greet-input");
|
|
||||||
greetMsgEl = document.querySelector("#greet-msg");
|
|
||||||
document.querySelector("#greet-form")?.addEventListener("submit", (e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
greet();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,116 +0,0 @@
|
|||||||
.logo.vite:hover {
|
|
||||||
filter: drop-shadow(0 0 2em #747bff);
|
|
||||||
}
|
|
||||||
|
|
||||||
.logo.typescript:hover {
|
|
||||||
filter: drop-shadow(0 0 2em #2d79c7);
|
|
||||||
}
|
|
||||||
:root {
|
|
||||||
font-family: Inter, Avenir, Helvetica, Arial, sans-serif;
|
|
||||||
font-size: 16px;
|
|
||||||
line-height: 24px;
|
|
||||||
font-weight: 400;
|
|
||||||
|
|
||||||
color: #0f0f0f;
|
|
||||||
background-color: #f6f6f6;
|
|
||||||
|
|
||||||
font-synthesis: none;
|
|
||||||
text-rendering: optimizeLegibility;
|
|
||||||
-webkit-font-smoothing: antialiased;
|
|
||||||
-moz-osx-font-smoothing: grayscale;
|
|
||||||
-webkit-text-size-adjust: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.container {
|
|
||||||
margin: 0;
|
|
||||||
padding-top: 10vh;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
justify-content: center;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.logo {
|
|
||||||
height: 6em;
|
|
||||||
padding: 1.5em;
|
|
||||||
will-change: filter;
|
|
||||||
transition: 0.75s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.logo.tauri:hover {
|
|
||||||
filter: drop-shadow(0 0 2em #24c8db);
|
|
||||||
}
|
|
||||||
|
|
||||||
.row {
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
a {
|
|
||||||
font-weight: 500;
|
|
||||||
color: #646cff;
|
|
||||||
text-decoration: inherit;
|
|
||||||
}
|
|
||||||
|
|
||||||
a:hover {
|
|
||||||
color: #535bf2;
|
|
||||||
}
|
|
||||||
|
|
||||||
h1 {
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
input,
|
|
||||||
button {
|
|
||||||
border-radius: 8px;
|
|
||||||
border: 1px solid transparent;
|
|
||||||
padding: 0.6em 1.2em;
|
|
||||||
font-size: 1em;
|
|
||||||
font-weight: 500;
|
|
||||||
font-family: inherit;
|
|
||||||
color: #0f0f0f;
|
|
||||||
background-color: #ffffff;
|
|
||||||
transition: border-color 0.25s;
|
|
||||||
box-shadow: 0 2px 2px rgba(0, 0, 0, 0.2);
|
|
||||||
}
|
|
||||||
|
|
||||||
button {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
button:hover {
|
|
||||||
border-color: #396cd8;
|
|
||||||
}
|
|
||||||
button:active {
|
|
||||||
border-color: #396cd8;
|
|
||||||
background-color: #e8e8e8;
|
|
||||||
}
|
|
||||||
|
|
||||||
input,
|
|
||||||
button {
|
|
||||||
outline: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
#greet-input {
|
|
||||||
margin-right: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (prefers-color-scheme: dark) {
|
|
||||||
:root {
|
|
||||||
color: #f6f6f6;
|
|
||||||
background-color: #2f2f2f;
|
|
||||||
}
|
|
||||||
|
|
||||||
a:hover {
|
|
||||||
color: #24c8db;
|
|
||||||
}
|
|
||||||
|
|
||||||
input,
|
|
||||||
button {
|
|
||||||
color: #ffffff;
|
|
||||||
background-color: #0f0f0f98;
|
|
||||||
}
|
|
||||||
button:active {
|
|
||||||
background-color: #0f0f0f69;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -15,6 +15,5 @@
|
|||||||
"noUnusedLocals": true,
|
"noUnusedLocals": true,
|
||||||
"noUnusedParameters": true,
|
"noUnusedParameters": true,
|
||||||
"noFallthroughCasesInSwitch": true
|
"noFallthroughCasesInSwitch": true
|
||||||
},
|
}
|
||||||
"include": ["src"]
|
|
||||||
}
|
}
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
import { defineConfig } from "vite";
|
|
||||||
|
|
||||||
// @ts-expect-error process is a nodejs global
|
|
||||||
const host = process.env.TAURI_DEV_HOST;
|
|
||||||
|
|
||||||
// https://vite.dev/config/
|
|
||||||
export default defineConfig(async () => ({
|
|
||||||
|
|
||||||
// Vite options tailored for Tauri development and only applied in `tauri dev` or `tauri build`
|
|
||||||
//
|
|
||||||
// 1. prevent Vite from obscuring rust errors
|
|
||||||
clearScreen: false,
|
|
||||||
// 2. tauri expects a fixed port, fail if that port is not available
|
|
||||||
server: {
|
|
||||||
port: 1420,
|
|
||||||
strictPort: true,
|
|
||||||
host: host || false,
|
|
||||||
hmr: host
|
|
||||||
? {
|
|
||||||
protocol: "ws",
|
|
||||||
host,
|
|
||||||
port: 1421,
|
|
||||||
}
|
|
||||||
: undefined,
|
|
||||||
watch: {
|
|
||||||
// 3. tell Vite to ignore watching `src-tauri`
|
|
||||||
ignored: ["**/src-tauri/**"],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
+20
-12
@@ -1,26 +1,34 @@
|
|||||||
{
|
{
|
||||||
"name": "@blitzkit/bot",
|
"name": "@blitzkit/bot",
|
||||||
"private": true,
|
|
||||||
"type": "module",
|
|
||||||
"types": "src/types.d.ts",
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@blitzkit/core": "workspace:*",
|
"@blitzkit/core": "workspace:*",
|
||||||
"@blitzkit/i18n": "workspace:*",
|
"@blitzkit/i18n": "workspace:*",
|
||||||
"satori": "^0.18.3",
|
|
||||||
"@resvg/resvg-js": "^2.6.2",
|
|
||||||
"discord.js": "^14.22.1",
|
|
||||||
"react": "^19.1.1",
|
|
||||||
"@radix-ui/colors": "^3.0.0",
|
"@radix-ui/colors": "^3.0.0",
|
||||||
"fuzzysort": "^3.1.0",
|
"@radix-ui/themes": "^3.2.1",
|
||||||
|
"@resvg/resvg-js": "^2.6.2",
|
||||||
|
"@types/adm-zip": "^0.5.7",
|
||||||
|
"@types/lodash-es": "^4.17.12",
|
||||||
|
"@types/markdown-escape": "^1.1.3",
|
||||||
|
"@types/react": "^19.2.2",
|
||||||
|
"adm-zip": "^0.5.16",
|
||||||
"bepaint": "^0.1.0-beta.3",
|
"bepaint": "^0.1.0-beta.3",
|
||||||
|
"discord.js": "^14.22.1",
|
||||||
"dotenv": "^17.2.2",
|
"dotenv": "^17.2.2",
|
||||||
"markdown-escape": "^2.0.0"
|
"fuzzysort": "^3.1.0",
|
||||||
|
"lodash-es": "^4.17.21",
|
||||||
|
"markdown-escape": "^2.0.0",
|
||||||
|
"pickleparser": "^0.2.1",
|
||||||
|
"prisma": "^6.17.1",
|
||||||
|
"protobufjs": "^7.5.4",
|
||||||
|
"react": "^19.2.0",
|
||||||
|
"satori": "^0.18.3",
|
||||||
|
"sharp": "^0.34.4"
|
||||||
},
|
},
|
||||||
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "bun --watch src/main.ts",
|
"dev": "bun --watch src/main.ts",
|
||||||
"start": "bun src/main.ts"
|
"start": "bun src/main.ts"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"type": "module",
|
||||||
"@types/markdown-escape": "^1.1.3"
|
"types": "src/types.d.ts"
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,28 +1,31 @@
|
|||||||
import { createLocalizedCommand } from '../core/discord/createLocalizedCommand';
|
import { createLocalizedCommand } from "../core/discord/createLocalizedCommand";
|
||||||
import { translator } from '../core/localization/translator';
|
import { translator } from "../core/localization/translator";
|
||||||
import { COMMANDS_RAW, CommandRegistry } from '../events/interactionCreate';
|
import {
|
||||||
|
COMMANDS_RAW,
|
||||||
|
type CommandRegistry,
|
||||||
|
} from "../events/interactionCreate";
|
||||||
|
|
||||||
const subcommands = [
|
const subcommands = [
|
||||||
'embeds',
|
"embeds",
|
||||||
'introduction',
|
"introduction",
|
||||||
'invite',
|
"invite",
|
||||||
'timezones',
|
"timezones",
|
||||||
'credits',
|
"credits",
|
||||||
] as const;
|
] as const;
|
||||||
type Subcommand = (typeof subcommands)[number];
|
type Subcommand = (typeof subcommands)[number];
|
||||||
|
|
||||||
const DOCS: Record<Subcommand, string> = {
|
const DOCS: Record<Subcommand, string> = {
|
||||||
embeds: 'guide/embeds',
|
embeds: "guide/embeds",
|
||||||
introduction: 'guide/introduction',
|
introduction: "guide/introduction",
|
||||||
invite: 'guide/invite',
|
invite: "guide/invite",
|
||||||
timezones: 'guide/timezones',
|
timezones: "guide/timezones",
|
||||||
credits: 'about/credits',
|
credits: "about/credits",
|
||||||
};
|
};
|
||||||
|
|
||||||
export const aboutCommand = new Promise<CommandRegistry>(async (resolve) => {
|
export const aboutCommand = new Promise<CommandRegistry>(async (resolve) => {
|
||||||
resolve({
|
resolve({
|
||||||
command: createLocalizedCommand('about', [
|
command: createLocalizedCommand("about", [
|
||||||
{ subcommand: 'commands' },
|
{ subcommand: "commands" },
|
||||||
...subcommands.map((subcommand) => ({ subcommand })),
|
...subcommands.map((subcommand) => ({ subcommand })),
|
||||||
]),
|
]),
|
||||||
|
|
||||||
@@ -30,7 +33,7 @@ export const aboutCommand = new Promise<CommandRegistry>(async (resolve) => {
|
|||||||
const subcommand = interaction.options.getSubcommand();
|
const subcommand = interaction.options.getSubcommand();
|
||||||
const { strings } = translator(interaction.locale);
|
const { strings } = translator(interaction.locale);
|
||||||
|
|
||||||
if (subcommand === 'commands') {
|
if (subcommand === "commands") {
|
||||||
return `${strings.bot.commands.about.subcommands.commands.body}${(
|
return `${strings.bot.commands.about.subcommands.commands.body}${(
|
||||||
await Promise.all(COMMANDS_RAW)
|
await Promise.all(COMMANDS_RAW)
|
||||||
)
|
)
|
||||||
@@ -40,7 +43,7 @@ export const aboutCommand = new Promise<CommandRegistry>(async (resolve) => {
|
|||||||
(b.command.name_localizations?.[interaction.locale] ??
|
(b.command.name_localizations?.[interaction.locale] ??
|
||||||
b.command.name)
|
b.command.name)
|
||||||
? -1
|
? -1
|
||||||
: 1,
|
: 1
|
||||||
)
|
)
|
||||||
.map(
|
.map(
|
||||||
(registry) =>
|
(registry) =>
|
||||||
@@ -51,9 +54,9 @@ export const aboutCommand = new Promise<CommandRegistry>(async (resolve) => {
|
|||||||
registry.command.description_localizations?.[
|
registry.command.description_localizations?.[
|
||||||
interaction.locale
|
interaction.locale
|
||||||
] ?? registry.command.description
|
] ?? registry.command.description
|
||||||
}`,
|
}`
|
||||||
)
|
)
|
||||||
.join('\n')}`;
|
.join("\n")}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
const url = `https://raw.githubusercontent.com/tresabhi/blitzkit/main/docs/${DOCS[subcommand as Subcommand]}.md`;
|
const url = `https://raw.githubusercontent.com/tresabhi/blitzkit/main/docs/${DOCS[subcommand as Subcommand]}.md`;
|
||||||
|
|||||||
@@ -1,144 +0,0 @@
|
|||||||
import {
|
|
||||||
BlitzTankClass,
|
|
||||||
Region,
|
|
||||||
regionToRegionSubdomain,
|
|
||||||
} from '@blitzkit/core';
|
|
||||||
import { literals } from '@blitzkit/i18n';
|
|
||||||
import { tankDefinitions } from '../core/blitzkit/nonBlockingPromises';
|
|
||||||
import { chunkLines } from '../core/discord/chunkLines';
|
|
||||||
import { createLocalizedCommand } from '../core/discord/createLocalizedCommand';
|
|
||||||
import { translator } from '../core/localization/translator';
|
|
||||||
import { CommandRegistry } from '../events/interactionCreate';
|
|
||||||
|
|
||||||
type Auction = null | {
|
|
||||||
count: number;
|
|
||||||
has_next: boolean;
|
|
||||||
results: Result[];
|
|
||||||
};
|
|
||||||
|
|
||||||
type Result =
|
|
||||||
| {
|
|
||||||
id?: number;
|
|
||||||
type: 'vehicle';
|
|
||||||
countable?: boolean;
|
|
||||||
entity?: Entity;
|
|
||||||
initial_count: number;
|
|
||||||
current_count: number;
|
|
||||||
saleable?: boolean;
|
|
||||||
available_from?: Date;
|
|
||||||
available_before?: Date;
|
|
||||||
price?: Price;
|
|
||||||
next_price: Price | null;
|
|
||||||
available: true;
|
|
||||||
display?: boolean;
|
|
||||||
next_price_datetime: Date;
|
|
||||||
next_price_timestamp: number;
|
|
||||||
}
|
|
||||||
| {
|
|
||||||
available: false;
|
|
||||||
type: 'vehicle';
|
|
||||||
};
|
|
||||||
|
|
||||||
interface Entity {
|
|
||||||
id: number;
|
|
||||||
name: string;
|
|
||||||
nation: string;
|
|
||||||
subnation: string;
|
|
||||||
use_subnation_flag: boolean;
|
|
||||||
type_slug: BlitzTankClass;
|
|
||||||
level: number;
|
|
||||||
roman_level: string;
|
|
||||||
user_string: string;
|
|
||||||
image_url: string;
|
|
||||||
preview_image_url: string;
|
|
||||||
is_premium: boolean;
|
|
||||||
is_collectible: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface Price {
|
|
||||||
currency: Currency;
|
|
||||||
value: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface Currency {
|
|
||||||
name: 'gold';
|
|
||||||
count: number;
|
|
||||||
title: 'Gold';
|
|
||||||
image_url: string;
|
|
||||||
sizes: unknown;
|
|
||||||
type: 'currency';
|
|
||||||
}
|
|
||||||
|
|
||||||
const WARNING_COUNT = 500;
|
|
||||||
|
|
||||||
export const auctionCommand = new Promise<CommandRegistry>((resolve) => {
|
|
||||||
resolve({
|
|
||||||
command: createLocalizedCommand('auction'),
|
|
||||||
|
|
||||||
async handler(interaction) {
|
|
||||||
const { strings } = translator(interaction.locale);
|
|
||||||
const awaitedTankDefinitions = await tankDefinitions;
|
|
||||||
const region: Region = 'com';
|
|
||||||
const pageSize = 80;
|
|
||||||
const saleable = true;
|
|
||||||
const data = await fetch(
|
|
||||||
`https://${regionToRegionSubdomain(
|
|
||||||
region,
|
|
||||||
)}.wotblitz.com/en/api/events/items/auction/?page_size=${
|
|
||||||
pageSize
|
|
||||||
}&type[]=vehicle&saleable=${saleable}`,
|
|
||||||
).then((response) => response.json() as Promise<Auction>);
|
|
||||||
|
|
||||||
if (data === null) {
|
|
||||||
return strings.bot.commands.auction.errors.no_auction;
|
|
||||||
}
|
|
||||||
|
|
||||||
const saleableTanks = data.results.filter((result) => result.available);
|
|
||||||
const nextPricesTimestamp = saleableTanks[0].next_price_timestamp;
|
|
||||||
|
|
||||||
const title = `# ${strings.bot.commands.auction.body.title}`;
|
|
||||||
const subtitle = `${literals(strings.bot.commands.auction.body.subtitle, [
|
|
||||||
`${saleableTanks.length} / ${data.results.length}`,
|
|
||||||
`<t:${nextPricesTimestamp}:R>`,
|
|
||||||
'<https://wotblitz.com/auction/>',
|
|
||||||
])}`;
|
|
||||||
const body = saleableTanks.map((data, index) => {
|
|
||||||
const tank = awaitedTankDefinitions.tanks[data.entity!.id];
|
|
||||||
|
|
||||||
if (!tank) return '';
|
|
||||||
|
|
||||||
const name = `[${tank.name}](<https://blitzkit.app/tanks/${
|
|
||||||
tank.slug
|
|
||||||
}>)`;
|
|
||||||
const next =
|
|
||||||
data.next_price === null
|
|
||||||
? ''
|
|
||||||
: `\n-# ${literals(strings.bot.commands.auction.body.next, [
|
|
||||||
`<:gold:1317173197082333244> ${data.next_price.value.toLocaleString(
|
|
||||||
interaction.locale,
|
|
||||||
)}`,
|
|
||||||
])}`;
|
|
||||||
const available = literals(
|
|
||||||
strings.bot.commands.auction.body.available,
|
|
||||||
[
|
|
||||||
data.current_count.toLocaleString(interaction.locale),
|
|
||||||
data.initial_count.toLocaleString(interaction.locale),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
const isOut = data.current_count === 0;
|
|
||||||
const outString = isOut ? '~~' : '';
|
|
||||||
const isLow = data.current_count <= WARNING_COUNT;
|
|
||||||
|
|
||||||
return `${index + 1}. ${
|
|
||||||
outString
|
|
||||||
}${name} <:gold:1317173197082333244> ${data.price!.value.toLocaleString(
|
|
||||||
interaction.locale,
|
|
||||||
)}${outString}\n-#${isLow ? ' ‼️ ' : ' '}${available}${isOut ? '' : next}`;
|
|
||||||
});
|
|
||||||
const header = `${title}\n${subtitle}`;
|
|
||||||
const lines = [header, ...body];
|
|
||||||
|
|
||||||
return chunkLines(lines, '\n\n');
|
|
||||||
},
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -13,7 +13,7 @@ import { resolvePeriodFromButton } from '../../core/discord/resolvePeriodFromBut
|
|||||||
import { resolvePeriodFromCommand } from '../../core/discord/resolvePeriodFromCommand';
|
import { resolvePeriodFromCommand } from '../../core/discord/resolvePeriodFromCommand';
|
||||||
import { resolvePlayerFromButton } from '../../core/discord/resolvePlayerFromButton';
|
import { resolvePlayerFromButton } from '../../core/discord/resolvePlayerFromButton';
|
||||||
import { resolvePlayerFromCommand } from '../../core/discord/resolvePlayerFromCommand';
|
import { resolvePlayerFromCommand } from '../../core/discord/resolvePlayerFromCommand';
|
||||||
import { CommandRegistry } from '../../events/interactionCreate';
|
import type { CommandRegistry } from '../../events/interactionCreate';
|
||||||
import { renderBreakdown } from './render';
|
import { renderBreakdown } from './render';
|
||||||
|
|
||||||
export const breakdownCommand = new Promise<CommandRegistry>(
|
export const breakdownCommand = new Promise<CommandRegistry>(
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import {
|
import {
|
||||||
BlitzStats,
|
type BlitzStats,
|
||||||
calculateWN8,
|
calculateWN8,
|
||||||
getAccountInfo,
|
getAccountInfo,
|
||||||
getClanAccountInfo,
|
getClanAccountInfo,
|
||||||
@@ -17,11 +17,11 @@ import { TitleBar } from "../../components/TitleBar";
|
|||||||
import { filtersToDescription } from "../../core/blitzkit/filtersToDescription";
|
import { filtersToDescription } from "../../core/blitzkit/filtersToDescription";
|
||||||
import { tankDefinitions } from "../../core/blitzkit/nonBlockingPromises";
|
import { tankDefinitions } from "../../core/blitzkit/nonBlockingPromises";
|
||||||
import { UserError } from "../../core/blitzkit/userError";
|
import { UserError } from "../../core/blitzkit/userError";
|
||||||
import { filterStats, StatFilters } from "../../core/blitzstars/filterStats";
|
import { filterStats, type StatFilters } from "../../core/blitzstars/filterStats";
|
||||||
import { getStatsInPeriod } from "../../core/blitzstars/getStatsInPeriod";
|
import { getStatsInPeriod } from "../../core/blitzstars/getStatsInPeriod";
|
||||||
import { blitzStarsTankAverages } from "../../core/blitzstars/tankAverages";
|
import { blitzStarsTankAverages } from "../../core/blitzstars/tankAverages";
|
||||||
import { ResolvedPeriod } from "../../core/discord/resolvePeriodFromCommand";
|
import type { ResolvedPeriod } from "../../core/discord/resolvePeriodFromCommand";
|
||||||
import { ResolvedPlayer } from "../../core/discord/resolvePlayerFromCommand";
|
import type { ResolvedPlayer } from "../../core/discord/resolvePlayerFromCommand";
|
||||||
import { translator } from "../../core/localization/translator";
|
import { translator } from "../../core/localization/translator";
|
||||||
|
|
||||||
const ROWS_PER_PAGE = 8;
|
const ROWS_PER_PAGE = 8;
|
||||||
@@ -193,9 +193,9 @@ export async function renderBreakdown(
|
|||||||
title={
|
title={
|
||||||
tankDefinition
|
tankDefinition
|
||||||
? unwrap(tankDefinition.name)
|
? unwrap(tankDefinition.name)
|
||||||
: literals(strings.bot.commands.breakdown.body.unknown_tank, [
|
: literals(strings.bot.commands.breakdown.body.unknown_tank, {
|
||||||
`${id}`,
|
id,
|
||||||
])
|
})
|
||||||
}
|
}
|
||||||
stats={[
|
stats={[
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
import packageJSON from '../../../../package.json';
|
import packageJSON from "../../../../package.json";
|
||||||
import { client } from '../core/discord/client';
|
import { client } from "../core/discord/client";
|
||||||
import { createLocalizedCommand } from '../core/discord/createLocalizedCommand';
|
import { createLocalizedCommand } from "../core/discord/createLocalizedCommand";
|
||||||
import { translator } from '../core/localization/translator';
|
import { translator } from "../core/localization/translator";
|
||||||
import { CommandRegistry } from '../events/interactionCreate';
|
import type { CommandRegistry } from "../events/interactionCreate";
|
||||||
|
|
||||||
const executionStart = new Date().getTime();
|
const executionStart = new Date().getTime();
|
||||||
|
|
||||||
export const debugCommand = new Promise<CommandRegistry>((resolve) => {
|
export const debugCommand = new Promise<CommandRegistry>((resolve) => {
|
||||||
resolve({
|
resolve({
|
||||||
command: createLocalizedCommand('debug'),
|
command: createLocalizedCommand("debug"),
|
||||||
|
|
||||||
async handler(interaction) {
|
async handler(interaction) {
|
||||||
const { strings } = translator(interaction.locale);
|
const { strings } = translator(interaction.locale);
|
||||||
@@ -23,15 +23,15 @@ export const debugCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
[
|
[
|
||||||
strings.bot.commands.debug.body.uptime,
|
strings.bot.commands.debug.body.uptime,
|
||||||
`${Math.floor((uptime / 1000 / 60 / 60) % 24)}h ${Math.floor(
|
`${Math.floor((uptime / 1000 / 60 / 60) % 24)}h ${Math.floor(
|
||||||
(uptime / 1000 / 60) % 60,
|
(uptime / 1000 / 60) % 60
|
||||||
)}m ${Math.floor((uptime / 1000) % 60)}s ${Math.floor(
|
)}m ${Math.floor((uptime / 1000) % 60)}s ${Math.floor(
|
||||||
uptime % 1000,
|
uptime % 1000
|
||||||
)}ms`,
|
)}ms`,
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
return `${strings.bot.commands.debug.body.title}${list
|
return `${strings.bot.commands.debug.body.title}${list
|
||||||
.map(([key, value]) => `- ${key}: ${value}`)
|
.map(([key, value]) => `- ${key}: ${value}`)
|
||||||
.join('\n')}`;
|
.join("\n")}`;
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -1,48 +1,48 @@
|
|||||||
import { emblemURL, getAccountInfo, getClanAccountInfo } from '@blitzkit/core';
|
import { emblemURL, getAccountInfo, getClanAccountInfo } from "@blitzkit/core";
|
||||||
import { Locale, SlashCommandSubcommandGroupBuilder } from 'discord.js';
|
import { Locale, SlashCommandSubcommandGroupBuilder } from "discord.js";
|
||||||
import { CommandWrapper } from '../components/CommandWrapper';
|
import { CommandWrapper } from "../components/CommandWrapper";
|
||||||
import * as Graph from '../components/Graph';
|
import * as Graph from "../components/Graph";
|
||||||
import { LineColor } from '../components/Graph/components/Line/constants';
|
import { LineColor } from "../components/Graph/components/Line/constants";
|
||||||
import { NoData } from '../components/NoData';
|
import { NoData } from "../components/NoData";
|
||||||
import { TitleBar } from '../components/TitleBar';
|
import { TitleBar } from "../components/TitleBar";
|
||||||
import { resolveTankId } from '../core/blitz/resolveTankId';
|
import { resolveTankId } from "../core/blitz/resolveTankId";
|
||||||
import { getBlitzStarsLinkButton } from '../core/blitzstars/getBlitzStarsLinkButton';
|
import { getBlitzStarsLinkButton } from "../core/blitzstars/getBlitzStarsLinkButton";
|
||||||
import { getPlayerHistories } from '../core/blitzstars/getPlayerHistories';
|
import { getPlayerHistories } from "../core/blitzstars/getPlayerHistories";
|
||||||
import { getTankHistories } from '../core/blitzstars/getTankHistories';
|
import { getTankHistories } from "../core/blitzstars/getTankHistories";
|
||||||
import { addPeriodSubCommands } from '../core/discord/addPeriodSubCommands';
|
import { addPeriodSubCommands } from "../core/discord/addPeriodSubCommands";
|
||||||
import { addTankChoices } from '../core/discord/addTankChoices';
|
import { addTankChoices } from "../core/discord/addTankChoices";
|
||||||
import { addUsernameChoices } from '../core/discord/addUsernameChoices';
|
import { addUsernameChoices } from "../core/discord/addUsernameChoices";
|
||||||
import { autocompleteTanks } from '../core/discord/autocompleteTanks';
|
import { autocompleteTanks } from "../core/discord/autocompleteTanks";
|
||||||
import { autocompleteUsername } from '../core/discord/autocompleteUsername';
|
import { autocompleteUsername } from "../core/discord/autocompleteUsername";
|
||||||
import { buttonRefresh } from '../core/discord/buttonRefresh';
|
import { buttonRefresh } from "../core/discord/buttonRefresh";
|
||||||
import { commandToURL } from '../core/discord/commandToURL';
|
import { commandToURL } from "../core/discord/commandToURL";
|
||||||
import { createLocalizedCommand } from '../core/discord/createLocalizedCommand';
|
import { createLocalizedCommand } from "../core/discord/createLocalizedCommand";
|
||||||
import { getCustomPeriodParams } from '../core/discord/getCustomPeriodParams';
|
import { getCustomPeriodParams } from "../core/discord/getCustomPeriodParams";
|
||||||
import { resolvePeriodFromButton } from '../core/discord/resolvePeriodFromButton';
|
import { resolvePeriodFromButton } from "../core/discord/resolvePeriodFromButton";
|
||||||
import {
|
import {
|
||||||
ResolvedPeriod,
|
type ResolvedPeriod,
|
||||||
resolvePeriodFromCommand,
|
resolvePeriodFromCommand,
|
||||||
} from '../core/discord/resolvePeriodFromCommand';
|
} from "../core/discord/resolvePeriodFromCommand";
|
||||||
import { resolvePlayerFromButton } from '../core/discord/resolvePlayerFromButton';
|
import { resolvePlayerFromButton } from "../core/discord/resolvePlayerFromButton";
|
||||||
import {
|
import {
|
||||||
ResolvedPlayer,
|
type ResolvedPlayer,
|
||||||
resolvePlayerFromCommand,
|
resolvePlayerFromCommand,
|
||||||
} from '../core/discord/resolvePlayerFromCommand';
|
} from "../core/discord/resolvePlayerFromCommand";
|
||||||
import { CommandRegistry } from '../events/interactionCreate';
|
import type { CommandRegistry } from "../events/interactionCreate";
|
||||||
|
|
||||||
type EvolutionStatType = 'player' | 'tank';
|
type EvolutionStatType = "player" | "tank";
|
||||||
|
|
||||||
async function render(
|
async function render(
|
||||||
{ region, id }: ResolvedPlayer,
|
{ region, id }: ResolvedPlayer,
|
||||||
{ start, end, name }: ResolvedPeriod,
|
{ start, end, name }: ResolvedPeriod,
|
||||||
type: 'player' | 'tank',
|
type: "player" | "tank",
|
||||||
tankId: number | null,
|
tankId: number | null,
|
||||||
locale: Locale,
|
locale: Locale
|
||||||
) {
|
) {
|
||||||
const accountInfo = await getAccountInfo(region, id);
|
const accountInfo = await getAccountInfo(region, id);
|
||||||
const clan = (await getClanAccountInfo(region, id, ['clan']))?.clan;
|
const clan = (await getClanAccountInfo(region, id, ["clan"]))?.clan;
|
||||||
const logo = clan ? emblemURL(clan.emblem_set_id) : undefined;
|
const logo = clan ? emblemURL(clan.emblem_set_id) : undefined;
|
||||||
const histories = await (type === 'player'
|
const histories = await (type === "player"
|
||||||
? getPlayerHistories(region, id, {
|
? getPlayerHistories(region, id, {
|
||||||
start,
|
start,
|
||||||
end,
|
end,
|
||||||
@@ -61,7 +61,7 @@ async function render(
|
|||||||
[
|
[
|
||||||
history.all.battles,
|
history.all.battles,
|
||||||
(history.all.wins / history.all.battles) * 100,
|
(history.all.wins / history.all.battles) * 100,
|
||||||
] as Graph.PlotItem,
|
] as Graph.PlotItem
|
||||||
);
|
);
|
||||||
const times = histories.map((history) => history.last_battle_time);
|
const times = histories.map((history) => history.last_battle_time);
|
||||||
const minTime = Math.min(...times);
|
const minTime = Math.min(...times);
|
||||||
@@ -82,7 +82,7 @@ async function render(
|
|||||||
verticalMargin={{
|
verticalMargin={{
|
||||||
min: minY,
|
min: minY,
|
||||||
max: maxY,
|
max: maxY,
|
||||||
suffix: '%',
|
suffix: "%",
|
||||||
precision: 2,
|
precision: 2,
|
||||||
}}
|
}}
|
||||||
horizontalMargin={{
|
horizontalMargin={{
|
||||||
@@ -110,22 +110,22 @@ async function render(
|
|||||||
export const evolutionCommand = new Promise<CommandRegistry>(
|
export const evolutionCommand = new Promise<CommandRegistry>(
|
||||||
async (resolve) => {
|
async (resolve) => {
|
||||||
resolve({
|
resolve({
|
||||||
command: createLocalizedCommand('evolution', [
|
command: createLocalizedCommand("evolution", [
|
||||||
{
|
{
|
||||||
group: 'player',
|
group: "player",
|
||||||
modify(option: SlashCommandSubcommandGroupBuilder) {
|
modify(option: SlashCommandSubcommandGroupBuilder) {
|
||||||
addPeriodSubCommands(option, (option) =>
|
addPeriodSubCommands(option, (option) =>
|
||||||
option.addStringOption(addUsernameChoices),
|
option.addStringOption(addUsernameChoices)
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
group: 'tank',
|
group: "tank",
|
||||||
modify(option: SlashCommandSubcommandGroupBuilder) {
|
modify(option: SlashCommandSubcommandGroupBuilder) {
|
||||||
addPeriodSubCommands(option, (option) =>
|
addPeriodSubCommands(option, (option) =>
|
||||||
option
|
option
|
||||||
.addStringOption(addTankChoices)
|
.addStringOption(addTankChoices)
|
||||||
.addStringOption(addUsernameChoices),
|
.addStringOption(addUsernameChoices)
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -136,9 +136,9 @@ export const evolutionCommand = new Promise<CommandRegistry>(
|
|||||||
interaction.options.getSubcommandGroup() as EvolutionStatType;
|
interaction.options.getSubcommandGroup() as EvolutionStatType;
|
||||||
const player = await resolvePlayerFromCommand(interaction);
|
const player = await resolvePlayerFromCommand(interaction);
|
||||||
const period = resolvePeriodFromCommand(player.region, interaction);
|
const period = resolvePeriodFromCommand(player.region, interaction);
|
||||||
const tankIdRaw = interaction.options.getString('tank')!;
|
const tankIdRaw = interaction.options.getString("tank")!;
|
||||||
const tankId =
|
const tankId =
|
||||||
commandGroup === 'tank'
|
commandGroup === "tank"
|
||||||
? await resolveTankId(tankIdRaw, interaction.locale)
|
? await resolveTankId(tankIdRaw, interaction.locale)
|
||||||
: null;
|
: null;
|
||||||
const path = commandToURL(interaction, {
|
const path = commandToURL(interaction, {
|
||||||
@@ -153,13 +153,13 @@ export const evolutionCommand = new Promise<CommandRegistry>(
|
|||||||
period,
|
period,
|
||||||
commandGroup,
|
commandGroup,
|
||||||
tankId,
|
tankId,
|
||||||
interaction.locale,
|
interaction.locale
|
||||||
),
|
),
|
||||||
buttonRefresh(interaction, path),
|
buttonRefresh(interaction, path),
|
||||||
await getBlitzStarsLinkButton(
|
await getBlitzStarsLinkButton(
|
||||||
player.region,
|
player.region,
|
||||||
player.id,
|
player.id,
|
||||||
tankId ?? undefined,
|
tankId ?? undefined
|
||||||
),
|
),
|
||||||
];
|
];
|
||||||
},
|
},
|
||||||
@@ -171,7 +171,7 @@ export const evolutionCommand = new Promise<CommandRegistry>(
|
|||||||
|
|
||||||
async button(interaction) {
|
async button(interaction) {
|
||||||
const url = new URL(`https://example.com/${interaction.customId}`);
|
const url = new URL(`https://example.com/${interaction.customId}`);
|
||||||
const path = url.pathname.split('/');
|
const path = url.pathname.split("/");
|
||||||
const commandGroup = path[2] as EvolutionStatType;
|
const commandGroup = path[2] as EvolutionStatType;
|
||||||
const player = await resolvePlayerFromButton(interaction);
|
const player = await resolvePlayerFromButton(interaction);
|
||||||
const period = resolvePeriodFromButton(player.region, interaction);
|
const period = resolvePeriodFromButton(player.region, interaction);
|
||||||
@@ -180,10 +180,10 @@ export const evolutionCommand = new Promise<CommandRegistry>(
|
|||||||
player,
|
player,
|
||||||
period,
|
period,
|
||||||
commandGroup,
|
commandGroup,
|
||||||
parseInt(url.searchParams.get('tankId') ?? '0') || null,
|
parseInt(url.searchParams.get("tankId") ?? "0") || null,
|
||||||
interaction.locale,
|
interaction.locale
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
);
|
);
|
||||||
@@ -11,7 +11,7 @@ import { NoData } from '../components/NoData';
|
|||||||
import { TierWeights } from '../components/TierWeights';
|
import { TierWeights } from '../components/TierWeights';
|
||||||
import { TitleBar } from '../components/TitleBar';
|
import { TitleBar } from '../components/TitleBar';
|
||||||
import { filtersToDescription } from '../core/blitzkit/filtersToDescription';
|
import { filtersToDescription } from '../core/blitzkit/filtersToDescription';
|
||||||
import { filterStats, StatFilters } from '../core/blitzstars/filterStats';
|
import { filterStats, type StatFilters } from '../core/blitzstars/filterStats';
|
||||||
import { getBlitzStarsLinkButton } from '../core/blitzstars/getBlitzStarsLinkButton';
|
import { getBlitzStarsLinkButton } from '../core/blitzstars/getBlitzStarsLinkButton';
|
||||||
import { getStatsInPeriod } from '../core/blitzstars/getStatsInPeriod';
|
import { getStatsInPeriod } from '../core/blitzstars/getStatsInPeriod';
|
||||||
import { addPeriodicFilterOptions } from '../core/discord/addPeriodicFilterOptions';
|
import { addPeriodicFilterOptions } from '../core/discord/addPeriodicFilterOptions';
|
||||||
@@ -26,15 +26,15 @@ import { getFiltersFromButton } from '../core/discord/getFiltersFromButton';
|
|||||||
import { getFiltersFromCommand } from '../core/discord/getFiltersFromCommand';
|
import { getFiltersFromCommand } from '../core/discord/getFiltersFromCommand';
|
||||||
import { resolvePeriodFromButton } from '../core/discord/resolvePeriodFromButton';
|
import { resolvePeriodFromButton } from '../core/discord/resolvePeriodFromButton';
|
||||||
import {
|
import {
|
||||||
ResolvedPeriod,
|
type ResolvedPeriod,
|
||||||
resolvePeriodFromCommand,
|
resolvePeriodFromCommand,
|
||||||
} from '../core/discord/resolvePeriodFromCommand';
|
} from '../core/discord/resolvePeriodFromCommand';
|
||||||
import { resolvePlayerFromButton } from '../core/discord/resolvePlayerFromButton';
|
import { resolvePlayerFromButton } from '../core/discord/resolvePlayerFromButton';
|
||||||
import {
|
import {
|
||||||
ResolvedPlayer,
|
type ResolvedPlayer,
|
||||||
resolvePlayerFromCommand,
|
resolvePlayerFromCommand,
|
||||||
} from '../core/discord/resolvePlayerFromCommand';
|
} from '../core/discord/resolvePlayerFromCommand';
|
||||||
import { CommandRegistry } from '../events/interactionCreate';
|
import type { CommandRegistry } from '../events/interactionCreate';
|
||||||
|
|
||||||
async function render(
|
async function render(
|
||||||
{ region, id }: ResolvedPlayer,
|
{ region, id }: ResolvedPlayer,
|
||||||
|
|||||||
@@ -1,44 +1,44 @@
|
|||||||
import { getAccountInfo, getClanInfo } from '@blitzkit/core';
|
import { getAccountInfo, getClanInfo } from "@blitzkit/core";
|
||||||
import { literals } from '@blitzkit/i18n';
|
import { literals } from "@blitzkit/i18n";
|
||||||
import { Locale } from 'discord.js';
|
import { Locale } from "discord.js";
|
||||||
import { CommandWrapper } from '../components/CommandWrapper';
|
import { CommandWrapper } from "../components/CommandWrapper";
|
||||||
import { GenericStats } from '../components/GenericStats';
|
import { GenericStats } from "../components/GenericStats";
|
||||||
import { NoData } from '../components/NoData';
|
import { NoData } from "../components/NoData";
|
||||||
import { TitleBar } from '../components/TitleBar';
|
import { TitleBar } from "../components/TitleBar";
|
||||||
import { addClanChoices } from '../core/discord/addClanChoices';
|
import { addClanChoices } from "../core/discord/addClanChoices";
|
||||||
import { autocompleteClan } from '../core/discord/autocompleteClan';
|
import { autocompleteClan } from "../core/discord/autocompleteClan";
|
||||||
import { createLocalizedCommand } from '../core/discord/createLocalizedCommand';
|
import { createLocalizedCommand } from "../core/discord/createLocalizedCommand";
|
||||||
import { localizationObject } from '../core/discord/localizationObject';
|
import { localizationObject } from "../core/discord/localizationObject";
|
||||||
import { resolveClanFromCommand } from '../core/discord/resolveClanFromCommand';
|
import { resolveClanFromCommand } from "../core/discord/resolveClanFromCommand";
|
||||||
import { translator } from '../core/localization/translator';
|
import { translator } from "../core/localization/translator";
|
||||||
import { CommandRegistry } from '../events/interactionCreate';
|
import type { CommandRegistry } from "../events/interactionCreate";
|
||||||
|
|
||||||
const DEFAULT_THRESHOLD = 7;
|
const DEFAULT_THRESHOLD = 7;
|
||||||
|
|
||||||
export const inactiveCommand = new Promise<CommandRegistry>((resolve) => {
|
export const inactiveCommand = new Promise<CommandRegistry>((resolve) => {
|
||||||
resolve({
|
resolve({
|
||||||
command: createLocalizedCommand('inactive')
|
command: createLocalizedCommand("inactive")
|
||||||
.addStringOption(addClanChoices)
|
.addStringOption(addClanChoices)
|
||||||
.addNumberOption((option) => {
|
.addNumberOption((option) => {
|
||||||
const { strings } = translator(Locale.EnglishUS);
|
const { strings } = translator(Locale.EnglishUS);
|
||||||
|
|
||||||
return option
|
return option
|
||||||
.setName('threshold')
|
.setName("threshold")
|
||||||
.setNameLocalizations(
|
.setNameLocalizations(
|
||||||
localizationObject(
|
localizationObject(
|
||||||
(strings) => strings.bot.commands.inactive.options.threshold.name,
|
(strings) => strings.bot.commands.inactive.options.threshold.name,
|
||||||
undefined,
|
undefined,
|
||||||
true,
|
true
|
||||||
),
|
)
|
||||||
)
|
)
|
||||||
.setDescription(
|
.setDescription(
|
||||||
strings.bot.commands.inactive.options.threshold.description,
|
strings.bot.commands.inactive.options.threshold.description
|
||||||
)
|
)
|
||||||
.setDescriptionLocalizations(
|
.setDescriptionLocalizations(
|
||||||
localizationObject(
|
localizationObject(
|
||||||
(strings) =>
|
(strings) =>
|
||||||
strings.bot.commands.inactive.options.threshold.description,
|
strings.bot.commands.inactive.options.threshold.description
|
||||||
),
|
)
|
||||||
)
|
)
|
||||||
.setMinValue(0);
|
.setMinValue(0);
|
||||||
}),
|
}),
|
||||||
@@ -47,7 +47,7 @@ export const inactiveCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
const { strings } = translator(interaction.locale);
|
const { strings } = translator(interaction.locale);
|
||||||
const { region, id } = await resolveClanFromCommand(interaction);
|
const { region, id } = await resolveClanFromCommand(interaction);
|
||||||
const threshold =
|
const threshold =
|
||||||
interaction.options.getNumber('threshold')! ?? DEFAULT_THRESHOLD;
|
interaction.options.getNumber("threshold")! ?? DEFAULT_THRESHOLD;
|
||||||
const time = new Date().getTime() / 1000;
|
const time = new Date().getTime() / 1000;
|
||||||
const clanInfo = await getClanInfo(region, id);
|
const clanInfo = await getClanInfo(region, id);
|
||||||
const accountInfo = await getAccountInfo(region, clanInfo.members_ids);
|
const accountInfo = await getAccountInfo(region, clanInfo.members_ids);
|
||||||
@@ -57,7 +57,7 @@ export const inactiveCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
[
|
[
|
||||||
account.nickname,
|
account.nickname,
|
||||||
(time - account.last_battle_time) / 60 / 60 / 24,
|
(time - account.last_battle_time) / 60 / 60 / 24,
|
||||||
] as [string, number],
|
] as [string, number]
|
||||||
)
|
)
|
||||||
.filter(([, inactiveDays]) => inactiveDays >= threshold)
|
.filter(([, inactiveDays]) => inactiveDays >= threshold)
|
||||||
.sort((a, b) => b[1] - a[1])
|
.sort((a, b) => b[1] - a[1])
|
||||||
@@ -65,10 +65,10 @@ export const inactiveCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
([name, days]) =>
|
([name, days]) =>
|
||||||
[
|
[
|
||||||
name,
|
name,
|
||||||
literals(strings.bot.commands.inactive.body.listing, [
|
literals(strings.bot.commands.inactive.body.listing, {
|
||||||
days.toFixed(0),
|
days: days.toFixed(0),
|
||||||
]),
|
}),
|
||||||
] as [string, string],
|
] as [string, string]
|
||||||
);
|
);
|
||||||
const hasInactiveMembers = inactive.length > 0;
|
const hasInactiveMembers = inactive.length > 0;
|
||||||
|
|
||||||
@@ -79,7 +79,7 @@ export const inactiveCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
image={`https://wotblitz-gc.gcdn.co/icons/clanEmblems1x/clan-icon-v2-${clanInfo.emblem_set_id}.png`}
|
image={`https://wotblitz-gc.gcdn.co/icons/clanEmblems1x/clan-icon-v2-${clanInfo.emblem_set_id}.png`}
|
||||||
description={`${literals(
|
description={`${literals(
|
||||||
strings.bot.commands.inactive.body.subtitle,
|
strings.bot.commands.inactive.body.subtitle,
|
||||||
[`${threshold}`],
|
{ days: threshold }
|
||||||
)} • ${new Date().toLocaleDateString(interaction.locale)}`}
|
)} • ${new Date().toLocaleDateString(interaction.locale)}`}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import { createLocalizedCommand } from '../core/discord/createLocalizedCommand';
|
|||||||
import { embedInfo } from '../core/discord/embedInfo';
|
import { embedInfo } from '../core/discord/embedInfo';
|
||||||
import { resolvePlayerFromCommand } from '../core/discord/resolvePlayerFromCommand';
|
import { resolvePlayerFromCommand } from '../core/discord/resolvePlayerFromCommand';
|
||||||
import { translator } from '../core/localization/translator';
|
import { translator } from '../core/localization/translator';
|
||||||
import { CommandRegistry } from '../events/interactionCreate';
|
import type { CommandRegistry } from '../events/interactionCreate';
|
||||||
import { theme } from '../stitches.config';
|
import { theme } from '../stitches.config';
|
||||||
|
|
||||||
export const verifyCommand = new Promise<CommandRegistry>((resolve) => {
|
export const verifyCommand = new Promise<CommandRegistry>((resolve) => {
|
||||||
|
|||||||
@@ -5,31 +5,31 @@ import {
|
|||||||
flags,
|
flags,
|
||||||
getAccountInfo,
|
getAccountInfo,
|
||||||
getTankStats,
|
getTankStats,
|
||||||
} from '@blitzkit/core';
|
} from "@blitzkit/core";
|
||||||
import { literals } from '@blitzkit/i18n';
|
import { literals } from "@blitzkit/i18n";
|
||||||
import markdownEscape from 'markdown-escape';
|
import markdownEscape from "markdown-escape";
|
||||||
import {
|
import {
|
||||||
gameDefinitions,
|
gameDefinitions,
|
||||||
tankDefinitions,
|
tankDefinitions,
|
||||||
} from '../core/blitzkit/nonBlockingPromises';
|
} from "../core/blitzkit/nonBlockingPromises";
|
||||||
import { addTierChoices } from '../core/discord/addTierChoices';
|
import { addTierChoices } from "../core/discord/addTierChoices";
|
||||||
import { addUsernameChoices } from '../core/discord/addUsernameChoices';
|
import { addUsernameChoices } from "../core/discord/addUsernameChoices";
|
||||||
import { autocompleteUsername } from '../core/discord/autocompleteUsername';
|
import { autocompleteUsername } from "../core/discord/autocompleteUsername";
|
||||||
import { chunkLines } from '../core/discord/chunkLines';
|
import { chunkLines } from "../core/discord/chunkLines";
|
||||||
import { createLocalizedCommand } from '../core/discord/createLocalizedCommand';
|
import { createLocalizedCommand } from "../core/discord/createLocalizedCommand";
|
||||||
import { resolvePlayerFromCommand } from '../core/discord/resolvePlayerFromCommand';
|
import { resolvePlayerFromCommand } from "../core/discord/resolvePlayerFromCommand";
|
||||||
import { translator } from '../core/localization/translator';
|
import { translator } from "../core/localization/translator";
|
||||||
import { CommandRegistry } from '../events/interactionCreate';
|
import { type CommandRegistry } from "../events/interactionCreate";
|
||||||
|
|
||||||
export const ownedTanksCommand = new Promise<CommandRegistry>((resolve) => {
|
export const ownedTanksCommand = new Promise<CommandRegistry>((resolve) => {
|
||||||
resolve({
|
resolve({
|
||||||
command: createLocalizedCommand('owned-tanks')
|
command: createLocalizedCommand("owned-tanks")
|
||||||
.addStringOption(addTierChoices)
|
.addStringOption(addTierChoices)
|
||||||
.addStringOption(addUsernameChoices),
|
.addStringOption(addUsernameChoices),
|
||||||
|
|
||||||
async handler(interaction) {
|
async handler(interaction) {
|
||||||
const { strings, unwrap } = translator(interaction.locale);
|
const { strings, unwrap } = translator(interaction.locale);
|
||||||
const tier = Number(interaction.options.getString('tier'));
|
const tier = Number(interaction.options.getString("tier"));
|
||||||
const { id, region } = await resolvePlayerFromCommand(interaction);
|
const { id, region } = await resolvePlayerFromCommand(interaction);
|
||||||
const accountInfo = await getAccountInfo(region, id);
|
const accountInfo = await getAccountInfo(region, id);
|
||||||
const tankStats = await getTankStats(region, id);
|
const tankStats = await getTankStats(region, id);
|
||||||
@@ -43,7 +43,7 @@ export const ownedTanksCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
tankStats.map(async (tankData) => ({
|
tankStats.map(async (tankData) => ({
|
||||||
tankDefinitions: (await tankDefinitions).tanks[tankData.tank_id]!,
|
tankDefinitions: (await tankDefinitions).tanks[tankData.tank_id]!,
|
||||||
id: tankData.tank_id,
|
id: tankData.tank_id,
|
||||||
})),
|
}))
|
||||||
)
|
)
|
||||||
).filter((tank) => tank.tankDefinitions?.tier === tier);
|
).filter((tank) => tank.tankDefinitions?.tier === tier);
|
||||||
const groupedTanks: Record<string, TankDefinition[]> = {};
|
const groupedTanks: Record<string, TankDefinition[]> = {};
|
||||||
@@ -60,25 +60,25 @@ export const ownedTanksCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
|
|
||||||
const awaitedTankDefinitions = await tankDefinitions;
|
const awaitedTankDefinitions = await tankDefinitions;
|
||||||
const awaitedGameDefinitions = await gameDefinitions;
|
const awaitedGameDefinitions = await gameDefinitions;
|
||||||
const title = literals(strings.bot.commands.owned_tanks.body.title, [
|
const title = literals(strings.bot.commands.owned_tanks.body.title, {
|
||||||
markdownEscape(accountInfo.nickname),
|
name: markdownEscape(accountInfo.nickname),
|
||||||
TIER_ROMAN_NUMERALS[tier],
|
tier: TIER_ROMAN_NUMERALS[tier],
|
||||||
]);
|
});
|
||||||
const tankList = tankStats
|
const tankList = tankStats
|
||||||
.map(({ tank_id }) => awaitedTankDefinitions.tanks[tank_id])
|
.map(({ tank_id }) => awaitedTankDefinitions.tanks[tank_id])
|
||||||
.filter((tank) => tank.tier === tier)
|
.filter((tank) => tank.tier === tier)
|
||||||
.sort(
|
.sort(
|
||||||
(a, b) =>
|
(a, b) =>
|
||||||
TANK_CLASSES.indexOf(a.class) - TANK_CLASSES.indexOf(b.class),
|
TANK_CLASSES.indexOf(a.class) - TANK_CLASSES.indexOf(b.class)
|
||||||
)
|
)
|
||||||
.sort(
|
.sort(
|
||||||
(a, b) =>
|
(a, b) =>
|
||||||
awaitedGameDefinitions.nations.indexOf(a.nation) -
|
awaitedGameDefinitions.nations.indexOf(a.nation) -
|
||||||
awaitedGameDefinitions.nations.indexOf(b.nation),
|
awaitedGameDefinitions.nations.indexOf(b.nation)
|
||||||
)
|
)
|
||||||
.map(
|
.map(
|
||||||
(tank) =>
|
(tank) =>
|
||||||
`[${flags[tank.nation]} ${markdownEscape(unwrap(tank.name))}](<https://blitzkit.app/tanks/${tank.slug}>)`,
|
`[${flags[tank.nation]} ${markdownEscape(unwrap(tank.name))}](<https://blitzkit.app/tanks/${tank.slug}>)`
|
||||||
);
|
);
|
||||||
const lines = [title, ...tankList];
|
const lines = [title, ...tankList];
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
import { literals } from '@blitzkit/i18n';
|
import { literals } from "@blitzkit/i18n";
|
||||||
import { createLocalizedCommand } from '../core/discord/createLocalizedCommand';
|
import { createLocalizedCommand } from "../core/discord/createLocalizedCommand";
|
||||||
import { translator } from '../core/localization/translator';
|
import { translator } from "../core/localization/translator";
|
||||||
import { CommandRegistry } from '../events/interactionCreate';
|
import { CommandRegistry } from "../events/interactionCreate";
|
||||||
|
|
||||||
export const permissionsCommand = new Promise<CommandRegistry>((resolve) => {
|
export const permissionsCommand = new Promise<CommandRegistry>((resolve) => {
|
||||||
resolve({
|
resolve({
|
||||||
command: createLocalizedCommand('permissions'),
|
command: createLocalizedCommand("permissions"),
|
||||||
|
|
||||||
async handler(interaction) {
|
async handler(interaction) {
|
||||||
const { strings } = translator(interaction.locale);
|
const { strings } = translator(interaction.locale);
|
||||||
@@ -14,33 +14,33 @@ export const permissionsCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
new Date().getDay() === 5 && new Date().getDate() === 13;
|
new Date().getDay() === 5 && new Date().getDate() === 13;
|
||||||
const permissions = [
|
const permissions = [
|
||||||
[
|
[
|
||||||
interaction.appPermissions?.has('ViewChannel'),
|
interaction.appPermissions?.has("ViewChannel"),
|
||||||
strings.bot.commands.permissions.body.view_channels,
|
strings.bot.commands.permissions.body.view_channels,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
interaction.appPermissions?.has('ReadMessageHistory'),
|
interaction.appPermissions?.has("ReadMessageHistory"),
|
||||||
strings.bot.commands.permissions.body.read_message_history,
|
strings.bot.commands.permissions.body.read_message_history,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
interaction.appPermissions?.has('AttachFiles'),
|
interaction.appPermissions?.has("AttachFiles"),
|
||||||
strings.bot.commands.permissions.body.attach_files,
|
strings.bot.commands.permissions.body.attach_files,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
interaction.appPermissions?.has('UseExternalEmojis'),
|
interaction.appPermissions?.has("UseExternalEmojis"),
|
||||||
strings.bot.commands.permissions.body.external_emojis,
|
strings.bot.commands.permissions.body.external_emojis,
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
const body = permissions
|
const body = permissions
|
||||||
.map(([hasPermission, description]) => {
|
.map(([hasPermission, description]) => {
|
||||||
if (hasPermission) {
|
if (hasPermission) {
|
||||||
return `${isFridayThe13th ? '😇' : '✅'} ${description}`;
|
return `${isFridayThe13th ? "😇" : "✅"} ${description}`;
|
||||||
} else {
|
} else {
|
||||||
return `${isFridayThe13th ? '💀' : '❌'} ${description}`;
|
return `${isFridayThe13th ? "💀" : "❌"} ${description}`;
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.join('\n');
|
.join("\n");
|
||||||
|
|
||||||
return literals(strings.bot.commands.permissions.body.title, [body]);
|
return literals(strings.bot.commands.permissions.body.title, { body });
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -1,15 +1,15 @@
|
|||||||
import { literals } from '@blitzkit/i18n';
|
import { literals } from "@blitzkit/i18n";
|
||||||
import { createLocalizedCommand } from '../core/discord/createLocalizedCommand';
|
import { createLocalizedCommand } from "../core/discord/createLocalizedCommand";
|
||||||
import { translator } from '../core/localization/translator';
|
import { translator } from "../core/localization/translator";
|
||||||
import { CommandRegistry } from '../events/interactionCreate';
|
import type { CommandRegistry } from "../events/interactionCreate";
|
||||||
|
|
||||||
export const pingCommand = new Promise<CommandRegistry>((resolve) => {
|
export const pingCommand = new Promise<CommandRegistry>((resolve) => {
|
||||||
resolve({
|
resolve({
|
||||||
handlesInteraction: true,
|
handlesInteraction: true,
|
||||||
|
|
||||||
command: createLocalizedCommand('ping', [
|
command: createLocalizedCommand("ping", [
|
||||||
{ subcommand: 'blitzkit' },
|
{ subcommand: "blitzkit" },
|
||||||
{ subcommand: 'wotb' },
|
{ subcommand: "wotb" },
|
||||||
]),
|
]),
|
||||||
|
|
||||||
async handler(interaction) {
|
async handler(interaction) {
|
||||||
@@ -17,17 +17,17 @@ export const pingCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
const subcommand = interaction.options.getSubcommand();
|
const subcommand = interaction.options.getSubcommand();
|
||||||
const executionStart = Date.now();
|
const executionStart = Date.now();
|
||||||
|
|
||||||
if (subcommand === 'blitzkit') {
|
if (subcommand === "blitzkit") {
|
||||||
await interaction.editReply(strings.bot.commands.ping.body.pong);
|
await interaction.editReply(strings.bot.commands.ping.body.pong);
|
||||||
} else {
|
} else {
|
||||||
await fetch('https://api.wotblitz.com/');
|
await fetch("https://api.wotblitz.com/");
|
||||||
}
|
}
|
||||||
|
|
||||||
const executionTime = Date.now() - executionStart;
|
const executionTime = Date.now() - executionStart;
|
||||||
interaction.editReply(
|
interaction.editReply(
|
||||||
literals(strings.bot.commands.ping.body.pong_with_time, [
|
literals(strings.bot.commands.ping.body.pong_with_time, {
|
||||||
`${Math.round(executionTime)}`,
|
time: executionTime.toFixed(0),
|
||||||
]),
|
})
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,19 +1,19 @@
|
|||||||
import { getAccountInfo } from '@blitzkit/core';
|
import { getAccountInfo } from "@blitzkit/core";
|
||||||
import { literals } from '@blitzkit/i18n';
|
import { literals } from "@blitzkit/i18n";
|
||||||
import markdownEscape from 'markdown-escape';
|
import markdownEscape from "markdown-escape";
|
||||||
import { addUsernameChoices } from '../core/discord/addUsernameChoices';
|
import { addUsernameChoices } from "../core/discord/addUsernameChoices";
|
||||||
import { autocompleteUsername } from '../core/discord/autocompleteUsername';
|
import { autocompleteUsername } from "../core/discord/autocompleteUsername";
|
||||||
import { createLocalizedCommand } from '../core/discord/createLocalizedCommand';
|
import { createLocalizedCommand } from "../core/discord/createLocalizedCommand";
|
||||||
import { embedInfo } from '../core/discord/embedInfo';
|
import { embedInfo } from "../core/discord/embedInfo";
|
||||||
import { markdownTable } from '../core/discord/markdownTable';
|
import { markdownTable } from "../core/discord/markdownTable";
|
||||||
import { resolvePlayerFromCommand } from '../core/discord/resolvePlayerFromCommand';
|
import { resolvePlayerFromCommand } from "../core/discord/resolvePlayerFromCommand";
|
||||||
import { translator } from '../core/localization/translator';
|
import { translator } from "../core/localization/translator";
|
||||||
import { CommandRegistry } from '../events/interactionCreate';
|
import { CommandRegistry } from "../events/interactionCreate";
|
||||||
|
|
||||||
export const playerInfoCommand = new Promise<CommandRegistry>((resolve) => {
|
export const playerInfoCommand = new Promise<CommandRegistry>((resolve) => {
|
||||||
resolve({
|
resolve({
|
||||||
command:
|
command:
|
||||||
createLocalizedCommand('player-info').addStringOption(addUsernameChoices),
|
createLocalizedCommand("player-info").addStringOption(addUsernameChoices),
|
||||||
|
|
||||||
async handler(interaction) {
|
async handler(interaction) {
|
||||||
const { strings } = translator(interaction.locale);
|
const { strings } = translator(interaction.locale);
|
||||||
@@ -22,9 +22,9 @@ export const playerInfoCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
const accountInfo = await getAccountInfo(region, id);
|
const accountInfo = await getAccountInfo(region, id);
|
||||||
|
|
||||||
return embedInfo(
|
return embedInfo(
|
||||||
literals(strings.bot.commands.player_info.body.title, [
|
literals(strings.bot.commands.player_info.body.title, {
|
||||||
markdownEscape(accountInfo.nickname),
|
name: markdownEscape(accountInfo.nickname),
|
||||||
]),
|
}),
|
||||||
|
|
||||||
markdownTable([
|
markdownTable([
|
||||||
[
|
[
|
||||||
@@ -51,16 +51,16 @@ export const playerInfoCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
[
|
[
|
||||||
strings.bot.commands.player_info.body.created,
|
strings.bot.commands.player_info.body.created,
|
||||||
new Date(accountInfo.created_at * 1000).toLocaleDateString(
|
new Date(accountInfo.created_at * 1000).toLocaleDateString(
|
||||||
interaction.locale,
|
interaction.locale
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
strings.bot.commands.player_info.body.last_battle,
|
strings.bot.commands.player_info.body.last_battle,
|
||||||
new Date(accountInfo.last_battle_time * 1000).toLocaleDateString(
|
new Date(accountInfo.last_battle_time * 1000).toLocaleDateString(
|
||||||
interaction.locale,
|
interaction.locale
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
]),
|
])
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -8,42 +8,42 @@ import {
|
|||||||
getRatingInfo,
|
getRatingInfo,
|
||||||
getRatingNeighbors,
|
getRatingNeighbors,
|
||||||
imgur,
|
imgur,
|
||||||
} from '@blitzkit/core';
|
} from "@blitzkit/core";
|
||||||
import { literals } from '@blitzkit/i18n';
|
import { literals } from "@blitzkit/i18n";
|
||||||
import { SlashCommandSubcommandBuilder } from 'discord.js';
|
import { SlashCommandSubcommandBuilder } from "discord.js";
|
||||||
import markdownEscape from 'markdown-escape';
|
import markdownEscape from "markdown-escape";
|
||||||
import { Glow } from '../components/AllStatsOverview/components/HeroStat/components/Glow';
|
import { Glow } from "../components/AllStatsOverview/components/HeroStat/components/Glow";
|
||||||
import { CommandWrapper } from '../components/CommandWrapper';
|
import { CommandWrapper } from "../components/CommandWrapper";
|
||||||
import { DeltaCaret } from '../components/DeltaCaret';
|
import { DeltaCaret } from "../components/DeltaCaret";
|
||||||
import { TitleBar } from '../components/TitleBar';
|
import { TitleBar } from "../components/TitleBar";
|
||||||
import { normalizeLeagueIcon } from '../core/blitz/normalizeLeagueIcon';
|
import { normalizeLeagueIcon } from "../core/blitz/normalizeLeagueIcon";
|
||||||
import { iconPng } from '../core/blitzkit/iconPng';
|
import { iconPng } from "../core/blitzkit/iconPng";
|
||||||
import { addUsernameChoices } from '../core/discord/addUsernameChoices';
|
import { addUsernameChoices } from "../core/discord/addUsernameChoices";
|
||||||
import { createLocalizedCommand } from '../core/discord/createLocalizedCommand';
|
import { createLocalizedCommand } from "../core/discord/createLocalizedCommand";
|
||||||
import { resolvePlayerFromCommand } from '../core/discord/resolvePlayerFromCommand';
|
import { resolvePlayerFromCommand } from "../core/discord/resolvePlayerFromCommand";
|
||||||
import { translator } from '../core/localization/translator';
|
import { translator } from "../core/localization/translator";
|
||||||
import { CommandRegistry } from '../events/interactionCreate';
|
import type { CommandRegistry } from "../events/interactionCreate";
|
||||||
import { theme } from '../stitches.config';
|
import { theme } from "../stitches.config";
|
||||||
|
|
||||||
const LEAGUE_ACCENT = [
|
const LEAGUE_ACCENT = [
|
||||||
'_purple',
|
"_purple",
|
||||||
'_sand',
|
"_sand",
|
||||||
'_amber',
|
"_amber",
|
||||||
'_mauve',
|
"_mauve",
|
||||||
'_brown',
|
"_brown",
|
||||||
] as const;
|
] as const;
|
||||||
|
|
||||||
export const ratingCommand = new Promise<CommandRegistry>((resolve) => {
|
export const ratingCommand = new Promise<CommandRegistry>((resolve) => {
|
||||||
resolve({
|
resolve({
|
||||||
command: createLocalizedCommand('rating', [
|
command: createLocalizedCommand("rating", [
|
||||||
{
|
{
|
||||||
subcommand: 'today',
|
subcommand: "today",
|
||||||
modify(option: SlashCommandSubcommandBuilder) {
|
modify(option: SlashCommandSubcommandBuilder) {
|
||||||
option.addStringOption(addUsernameChoices);
|
option.addStringOption(addUsernameChoices);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
subcommand: 'season',
|
subcommand: "season",
|
||||||
modify(option: SlashCommandSubcommandBuilder) {
|
modify(option: SlashCommandSubcommandBuilder) {
|
||||||
option.addStringOption(addUsernameChoices);
|
option.addStringOption(addUsernameChoices);
|
||||||
},
|
},
|
||||||
@@ -52,11 +52,11 @@ export const ratingCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
|
|
||||||
async handler(interaction) {
|
async handler(interaction) {
|
||||||
const subcommand = interaction.options.getSubcommand(true) as
|
const subcommand = interaction.options.getSubcommand(true) as
|
||||||
| 'season'
|
| "season"
|
||||||
| 'today';
|
| "today";
|
||||||
const { strings } = translator(interaction.locale);
|
const { strings } = translator(interaction.locale);
|
||||||
const { id, region } = await resolvePlayerFromCommand(interaction);
|
const { id, region } = await resolvePlayerFromCommand(interaction);
|
||||||
const clan = (await getClanAccountInfo(region, id, ['clan']))?.clan;
|
const clan = (await getClanAccountInfo(region, id, ["clan"]))?.clan;
|
||||||
const clanImage = clan ? emblemURL(clan.emblem_set_id) : undefined;
|
const clanImage = clan ? emblemURL(clan.emblem_set_id) : undefined;
|
||||||
|
|
||||||
const ratingInfo = await getRatingInfo(region);
|
const ratingInfo = await getRatingInfo(region);
|
||||||
@@ -67,20 +67,20 @@ export const ratingCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
|
|
||||||
const leaderboard = await getArchivedRatingLeaderboard(
|
const leaderboard = await getArchivedRatingLeaderboard(
|
||||||
region,
|
region,
|
||||||
ratingInfo.current_season - (subcommand === 'today' ? 0 : 1),
|
ratingInfo.current_season - (subcommand === "today" ? 0 : 1)
|
||||||
);
|
);
|
||||||
|
|
||||||
if (leaderboard.version!.$case === 'v1') {
|
if (leaderboard.version!.$case === "v1") {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
'Encountered bkrl minimal format in latest season. Wait till next cron?',
|
"Encountered bkrl minimal format in latest season. Wait till next cron?"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const accountInfo = await getAccountInfo(region, id, [
|
const accountInfo = await getAccountInfo(region, id, [
|
||||||
'statistics.rating',
|
"statistics.rating",
|
||||||
]);
|
]);
|
||||||
const statsIndex = leaderboard.version!.value.entries.findIndex(
|
const statsIndex = leaderboard.version!.value.entries.findIndex(
|
||||||
(entry) => entry.id === id,
|
(entry) => entry.id === id
|
||||||
);
|
);
|
||||||
const statsA = leaderboard
|
const statsA = leaderboard
|
||||||
? leaderboard.version!.value.entries[statsIndex!]
|
? leaderboard.version!.value.entries[statsIndex!]
|
||||||
@@ -90,9 +90,9 @@ export const ratingCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
const statsB2Array = (await getRatingNeighbors(region, id, 0)).neighbors;
|
const statsB2Array = (await getRatingNeighbors(region, id, 0)).neighbors;
|
||||||
|
|
||||||
if (statsB2Array === undefined) {
|
if (statsB2Array === undefined) {
|
||||||
return literals(strings.bot.commands.rating.errors.no_participation, [
|
return literals(strings.bot.commands.rating.errors.no_participation, {
|
||||||
markdownEscape(accountInfo.nickname),
|
name: markdownEscape(accountInfo.nickname),
|
||||||
]);
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const [statsB2] = statsB2Array;
|
const [statsB2] = statsB2Array;
|
||||||
@@ -102,15 +102,15 @@ export const ratingCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
return strings.bot.commands.rating.errors.unrecorded_stats;
|
return strings.bot.commands.rating.errors.unrecorded_stats;
|
||||||
}
|
}
|
||||||
if (!statsB1) {
|
if (!statsB1) {
|
||||||
return literals(strings.bot.commands.rating.errors.no_participation, [
|
return literals(strings.bot.commands.rating.errors.no_participation, {
|
||||||
markdownEscape(accountInfo.nickname),
|
name: markdownEscape(accountInfo.nickname),
|
||||||
]);
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const reward = ratingInfo.rewards.find(
|
const reward = ratingInfo.rewards.find(
|
||||||
(reward) =>
|
(reward) =>
|
||||||
statsB2.number >= reward.from_position &&
|
statsB2.number >= reward.from_position &&
|
||||||
statsB2.number <= reward.to_position,
|
statsB2.number <= reward.to_position
|
||||||
);
|
);
|
||||||
const positionDelta = leaderboard
|
const positionDelta = leaderboard
|
||||||
? statsB2.number - positionA!
|
? statsB2.number - positionA!
|
||||||
@@ -118,11 +118,11 @@ export const ratingCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
const delta = deltaBkrlBlitzStats(
|
const delta = deltaBkrlBlitzStats(
|
||||||
statsA,
|
statsA,
|
||||||
accountInfo.statistics.rating!,
|
accountInfo.statistics.rating!,
|
||||||
statsB2,
|
statsB2
|
||||||
);
|
);
|
||||||
const leagueTheme = LEAGUE_ACCENT[league.index];
|
const leagueTheme = LEAGUE_ACCENT[league.index];
|
||||||
let rewardImage = reward
|
let rewardImage = reward
|
||||||
? reward.type === 'vehicle'
|
? reward.type === "vehicle"
|
||||||
? reward.vehicle.preview_image_url
|
? reward.vehicle.preview_image_url
|
||||||
: reward.stuff.image_url
|
: reward.stuff.image_url
|
||||||
: undefined;
|
: undefined;
|
||||||
@@ -131,7 +131,7 @@ export const ratingCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
const { ok } = await fetch(rewardImage);
|
const { ok } = await fetch(rewardImage);
|
||||||
|
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
rewardImage = imgur('kP88vqr');
|
rewardImage = imgur("kP88vqr");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -147,24 +147,24 @@ export const ratingCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
|
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
position: 'relative',
|
position: "relative",
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
overflow: 'hidden',
|
overflow: "hidden",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
position: 'relative',
|
position: "relative",
|
||||||
padding: 16,
|
padding: 16,
|
||||||
backgroundColor: theme.colors[`appBackground2${leagueTheme}`],
|
backgroundColor: theme.colors[`appBackground2${leagueTheme}`],
|
||||||
borderRadius: 4,
|
borderRadius: 4,
|
||||||
border: `1px solid ${
|
border: `1px solid ${
|
||||||
theme.colors[`componentInteractive${leagueTheme}`]
|
theme.colors[`componentInteractive${leagueTheme}`]
|
||||||
}`,
|
}`,
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
alignItems: 'center',
|
alignItems: "center",
|
||||||
justifyContent: 'space-between',
|
justifyContent: "space-between",
|
||||||
width: '100%',
|
width: "100%",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{reward === undefined && (
|
{reward === undefined && (
|
||||||
@@ -172,17 +172,17 @@ export const ratingCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
endOpacity={3 / 4}
|
endOpacity={3 / 4}
|
||||||
color={theme.colors[`solidBackground${leagueTheme}`]}
|
color={theme.colors[`solidBackground${leagueTheme}`]}
|
||||||
style={{
|
style={{
|
||||||
transform: 'translateX(-16px) rotate(90deg)',
|
transform: "translateX(-16px) rotate(90deg)",
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
gap: 8,
|
gap: 8,
|
||||||
justifyContent: 'center',
|
justifyContent: "center",
|
||||||
alignItems: 'center',
|
alignItems: "center",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<img
|
<img
|
||||||
@@ -190,24 +190,24 @@ export const ratingCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
style={{
|
style={{
|
||||||
width: 64,
|
width: 64,
|
||||||
height: 64,
|
height: 64,
|
||||||
objectFit: 'contain',
|
objectFit: "contain",
|
||||||
}}
|
}}
|
||||||
src={normalizeLeagueIcon(
|
src={normalizeLeagueIcon(
|
||||||
ratingInfo.leagues[league.index].big_icon,
|
ratingInfo.leagues[league.index].big_icon
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
flexDirection: 'column',
|
flexDirection: "column",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
alignItems: 'center',
|
alignItems: "center",
|
||||||
justifyContent: 'flex-start',
|
justifyContent: "flex-start",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
@@ -232,7 +232,7 @@ export const ratingCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{Math.abs(delta.score).toLocaleString(
|
{Math.abs(delta.score).toLocaleString(
|
||||||
interaction.locale,
|
interaction.locale
|
||||||
)}
|
)}
|
||||||
</span>
|
</span>
|
||||||
</>
|
</>
|
||||||
@@ -241,9 +241,9 @@ export const ratingCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
|
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
alignItems: 'center',
|
alignItems: "center",
|
||||||
justifyContent: 'flex-start',
|
justifyContent: "flex-start",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
@@ -267,7 +267,7 @@ export const ratingCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{Math.abs(positionDelta).toLocaleString(
|
{Math.abs(positionDelta).toLocaleString(
|
||||||
interaction.locale,
|
interaction.locale
|
||||||
)}
|
)}
|
||||||
</span>
|
</span>
|
||||||
</>
|
</>
|
||||||
@@ -279,23 +279,23 @@ export const ratingCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
{reward && (
|
{reward && (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
gap: 8,
|
gap: 8,
|
||||||
justifyContent: 'center',
|
justifyContent: "center",
|
||||||
alignItems: 'center',
|
alignItems: "center",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
flexDirection: 'column',
|
flexDirection: "column",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
alignItems: 'center',
|
alignItems: "center",
|
||||||
justifyContent: 'flex-end',
|
justifyContent: "flex-end",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
@@ -303,13 +303,13 @@ export const ratingCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
color: theme.colors[`textHighContrast${leagueTheme}`],
|
color: theme.colors[`textHighContrast${leagueTheme}`],
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
maxWidth: 136,
|
maxWidth: 136,
|
||||||
textAlign: 'right',
|
textAlign: "right",
|
||||||
whiteSpace: 'nowrap',
|
whiteSpace: "nowrap",
|
||||||
textOverflow: 'ellipsis',
|
textOverflow: "ellipsis",
|
||||||
overflow: 'hidden',
|
overflow: "hidden",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{reward.type === 'vehicle'
|
{reward.type === "vehicle"
|
||||||
? reward.vehicle.user_string
|
? reward.vehicle.user_string
|
||||||
: reward.stuff.title}
|
: reward.stuff.title}
|
||||||
</span>
|
</span>
|
||||||
@@ -317,9 +317,9 @@ export const ratingCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
|
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
alignItems: 'center',
|
alignItems: "center",
|
||||||
justifyContent: 'flex-end',
|
justifyContent: "flex-end",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
@@ -329,7 +329,7 @@ export const ratingCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Reward
|
Reward
|
||||||
{reward.type === 'stuff' ? ` x${reward.count}` : ''}
|
{reward.type === "stuff" ? ` x${reward.count}` : ""}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -338,7 +338,7 @@ export const ratingCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
style={{
|
style={{
|
||||||
width: 64,
|
width: 64,
|
||||||
height: 64,
|
height: 64,
|
||||||
objectFit: 'cover',
|
objectFit: "cover",
|
||||||
}}
|
}}
|
||||||
src={await iconPng(rewardImage!)}
|
src={await iconPng(rewardImage!)}
|
||||||
/>
|
/>
|
||||||
@@ -350,7 +350,7 @@ export const ratingCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
endOpacity={3 / 4}
|
endOpacity={3 / 4}
|
||||||
color={theme.colors[`solidBackground${leagueTheme}`]}
|
color={theme.colors[`solidBackground${leagueTheme}`]}
|
||||||
style={{
|
style={{
|
||||||
transform: 'translateX(16px) rotate(-90deg)',
|
transform: "translateX(16px) rotate(-90deg)",
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
@@ -362,10 +362,10 @@ export const ratingCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
direction="reverse"
|
direction="reverse"
|
||||||
color={theme.colors[`solidBackground${leagueTheme}`]}
|
color={theme.colors[`solidBackground${leagueTheme}`]}
|
||||||
style={{
|
style={{
|
||||||
position: 'absolute',
|
position: "absolute",
|
||||||
top: -40,
|
top: -40,
|
||||||
left: '50%',
|
left: "50%",
|
||||||
transform: 'translateX(-50%)',
|
transform: "translateX(-50%)",
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
@@ -373,32 +373,32 @@ export const ratingCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
<Glow
|
<Glow
|
||||||
color={theme.colors[`solidBackground${leagueTheme}`]}
|
color={theme.colors[`solidBackground${leagueTheme}`]}
|
||||||
style={{
|
style={{
|
||||||
position: 'absolute',
|
position: "absolute",
|
||||||
bottom: -40,
|
bottom: -40,
|
||||||
left: '50%',
|
left: "50%",
|
||||||
transform: 'translateX(-50%)',
|
transform: "translateX(-50%)",
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{delta.battles > 0 && (
|
{delta.battles > 0 && (
|
||||||
<div style={{ padding: '8px 0', display: 'flex' }}>
|
<div style={{ padding: "8px 0", display: "flex" }}>
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
alignItems: 'center',
|
alignItems: "center",
|
||||||
justifyContent: 'center',
|
justifyContent: "center",
|
||||||
gap: 4,
|
gap: 4,
|
||||||
flex: 1,
|
flex: 1,
|
||||||
flexDirection: 'column',
|
flexDirection: "column",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
style={{
|
style={{
|
||||||
fontSize: 24,
|
fontSize: 24,
|
||||||
color: theme.colors.textHighContrast,
|
color: theme.colors.textHighContrast,
|
||||||
fontWeight: 'bold',
|
fontWeight: "bold",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{delta.battles.toLocaleString(interaction.locale)}
|
{delta.battles.toLocaleString(interaction.locale)}
|
||||||
@@ -414,19 +414,19 @@ export const ratingCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
alignItems: 'center',
|
alignItems: "center",
|
||||||
justifyContent: 'center',
|
justifyContent: "center",
|
||||||
gap: 4,
|
gap: 4,
|
||||||
flex: 1,
|
flex: 1,
|
||||||
flexDirection: 'column',
|
flexDirection: "column",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
style={{
|
style={{
|
||||||
fontSize: 24,
|
fontSize: 24,
|
||||||
color: theme.colors.textHighContrast,
|
color: theme.colors.textHighContrast,
|
||||||
fontWeight: 'bold',
|
fontWeight: "bold",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{(100 * (delta.wins / delta.battles)).toFixed(0)}%
|
{(100 * (delta.wins / delta.battles)).toFixed(0)}%
|
||||||
@@ -442,23 +442,23 @@ export const ratingCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
alignItems: 'center',
|
alignItems: "center",
|
||||||
justifyContent: 'center',
|
justifyContent: "center",
|
||||||
gap: 4,
|
gap: 4,
|
||||||
flex: 1,
|
flex: 1,
|
||||||
flexDirection: 'column',
|
flexDirection: "column",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
style={{
|
style={{
|
||||||
fontSize: 24,
|
fontSize: 24,
|
||||||
color: theme.colors.textHighContrast,
|
color: theme.colors.textHighContrast,
|
||||||
fontWeight: 'bold',
|
fontWeight: "bold",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{Math.round(delta.damage / delta.battles).toLocaleString(
|
{Math.round(delta.damage / delta.battles).toLocaleString(
|
||||||
interaction.locale,
|
interaction.locale
|
||||||
)}
|
)}
|
||||||
</span>
|
</span>
|
||||||
<span
|
<span
|
||||||
@@ -472,19 +472,19 @@ export const ratingCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
alignItems: 'center',
|
alignItems: "center",
|
||||||
justifyContent: 'center',
|
justifyContent: "center",
|
||||||
gap: 4,
|
gap: 4,
|
||||||
flex: 1,
|
flex: 1,
|
||||||
flexDirection: 'column',
|
flexDirection: "column",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
style={{
|
style={{
|
||||||
fontSize: 24,
|
fontSize: 24,
|
||||||
color: theme.colors.textHighContrast,
|
color: theme.colors.textHighContrast,
|
||||||
fontWeight: 'bold',
|
fontWeight: "bold",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{(100 * (delta.survived / delta.battles)).toFixed(0)}%
|
{(100 * (delta.survived / delta.battles)).toFixed(0)}%
|
||||||
@@ -500,19 +500,19 @@ export const ratingCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
alignItems: 'center',
|
alignItems: "center",
|
||||||
justifyContent: 'center',
|
justifyContent: "center",
|
||||||
gap: 4,
|
gap: 4,
|
||||||
flex: 1,
|
flex: 1,
|
||||||
flexDirection: 'column',
|
flexDirection: "column",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
style={{
|
style={{
|
||||||
fontSize: 24,
|
fontSize: 24,
|
||||||
color: theme.colors.textHighContrast,
|
color: theme.colors.textHighContrast,
|
||||||
fontWeight: 'bold',
|
fontWeight: "bold",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{(delta.kills / delta.battles).toFixed(2)}
|
{(delta.kills / delta.battles).toFixed(2)}
|
||||||
|
|||||||
@@ -10,30 +10,30 @@ import {
|
|||||||
imgur,
|
imgur,
|
||||||
isOnGoingRatingSeason,
|
isOnGoingRatingSeason,
|
||||||
LEAGUES,
|
LEAGUES,
|
||||||
RatingInfo,
|
type RatingInfo,
|
||||||
RatingLeaderboard,
|
RatingLeaderboard,
|
||||||
Region,
|
type Region,
|
||||||
} from '@blitzkit/core';
|
} from "@blitzkit/core";
|
||||||
import { literals } from '@blitzkit/i18n';
|
import { literals } from "@blitzkit/i18n";
|
||||||
import {
|
import {
|
||||||
APIApplicationCommandOptionChoice,
|
type APIApplicationCommandOptionChoice,
|
||||||
Locale,
|
Locale,
|
||||||
SlashCommandSubcommandBuilder,
|
SlashCommandSubcommandBuilder,
|
||||||
} from 'discord.js';
|
} from "discord.js";
|
||||||
import { range } from 'lodash-es';
|
import { range } from "lodash-es";
|
||||||
import markdownEscape from 'markdown-escape';
|
import markdownEscape from "markdown-escape";
|
||||||
import { CommandWrapper } from '../components/CommandWrapper';
|
import { CommandWrapper } from "../components/CommandWrapper";
|
||||||
import * as Leaderboard from '../components/Leaderboard';
|
import * as Leaderboard from "../components/Leaderboard";
|
||||||
import { TitleBar } from '../components/TitleBar';
|
import { TitleBar } from "../components/TitleBar";
|
||||||
import { UserError } from '../core/blitzkit/userError';
|
import { UserError } from "../core/blitzkit/userError";
|
||||||
import { addRegionChoices } from '../core/discord/addRegionChoices';
|
import { addRegionChoices } from "../core/discord/addRegionChoices";
|
||||||
import { addUsernameChoices } from '../core/discord/addUsernameChoices';
|
import { addUsernameChoices } from "../core/discord/addUsernameChoices";
|
||||||
import { autocompleteUsername } from '../core/discord/autocompleteUsername';
|
import { autocompleteUsername } from "../core/discord/autocompleteUsername";
|
||||||
import { createLocalizedCommand } from '../core/discord/createLocalizedCommand';
|
import { createLocalizedCommand } from "../core/discord/createLocalizedCommand";
|
||||||
import { localizationObject } from '../core/discord/localizationObject';
|
import { localizationObject } from "../core/discord/localizationObject";
|
||||||
import { resolvePlayerFromCommand } from '../core/discord/resolvePlayerFromCommand';
|
import { resolvePlayerFromCommand } from "../core/discord/resolvePlayerFromCommand";
|
||||||
import { translator } from '../core/localization/translator';
|
import { translator } from "../core/localization/translator";
|
||||||
import { CommandRegistry } from '../events/interactionCreate';
|
import type { CommandRegistry } from "../events/interactionCreate";
|
||||||
|
|
||||||
interface SimplifiedPlayer {
|
interface SimplifiedPlayer {
|
||||||
id: number;
|
id: number;
|
||||||
@@ -51,7 +51,7 @@ export const ratingLeaderboardCommand = new Promise<CommandRegistry>(
|
|||||||
const onGoingSeason = await isOnGoingRatingSeason();
|
const onGoingSeason = await isOnGoingRatingSeason();
|
||||||
const seasonNumbers = range(
|
const seasonNumbers = range(
|
||||||
FIRST_MINIMAL_ARCHIVED_RATING_SEASON,
|
FIRST_MINIMAL_ARCHIVED_RATING_SEASON,
|
||||||
latestArchivedSeasonNumber + (onGoingSeason ? 1 : 0) + 1,
|
latestArchivedSeasonNumber + (onGoingSeason ? 1 : 0) + 1
|
||||||
);
|
);
|
||||||
|
|
||||||
function addOptions(option: SlashCommandSubcommandBuilder) {
|
function addOptions(option: SlashCommandSubcommandBuilder) {
|
||||||
@@ -66,51 +66,50 @@ export const ratingLeaderboardCommand = new Promise<CommandRegistry>(
|
|||||||
(strings) =>
|
(strings) =>
|
||||||
strings.bot.commands.rating_leaderboard.options.limit.name,
|
strings.bot.commands.rating_leaderboard.options.limit.name,
|
||||||
undefined,
|
undefined,
|
||||||
true,
|
true
|
||||||
),
|
)
|
||||||
)
|
)
|
||||||
.setDescription(
|
.setDescription(
|
||||||
literals(
|
literals(
|
||||||
strings.bot.commands.rating_leaderboard.options.limit
|
strings.bot.commands.rating_leaderboard.options.limit
|
||||||
.description,
|
.description,
|
||||||
[`${DEFAULT_LIMIT}`],
|
{ count: DEFAULT_LIMIT }
|
||||||
),
|
)
|
||||||
)
|
)
|
||||||
.setDescriptionLocalizations(
|
.setDescriptionLocalizations(
|
||||||
localizationObject(
|
localizationObject(
|
||||||
(strings) =>
|
(strings) =>
|
||||||
strings.bot.commands.rating_leaderboard.options.limit
|
strings.bot.commands.rating_leaderboard.options.limit
|
||||||
.description,
|
.description,
|
||||||
[`${DEFAULT_LIMIT}`],
|
{ count: DEFAULT_LIMIT }
|
||||||
),
|
)
|
||||||
)
|
)
|
||||||
.setRequired(false)
|
.setRequired(false)
|
||||||
.setMinValue(5)
|
.setMinValue(5)
|
||||||
.setMaxValue(30),
|
.setMaxValue(30)
|
||||||
)
|
)
|
||||||
.addStringOption((option) =>
|
.addStringOption((option) =>
|
||||||
option
|
option
|
||||||
.setName(
|
.setName(
|
||||||
strings.bot.commands.rating_leaderboard.options.season.name,
|
strings.bot.commands.rating_leaderboard.options.season.name
|
||||||
)
|
)
|
||||||
.setNameLocalizations(
|
.setNameLocalizations(
|
||||||
localizationObject(
|
localizationObject(
|
||||||
(strings) =>
|
(strings) =>
|
||||||
strings.bot.commands.rating_leaderboard.options.season.name,
|
strings.bot.commands.rating_leaderboard.options.season.name,
|
||||||
undefined,
|
undefined,
|
||||||
true,
|
true
|
||||||
),
|
)
|
||||||
)
|
)
|
||||||
.setDescription(
|
.setDescription(
|
||||||
strings.bot.commands.rating_leaderboard.options.season
|
strings.bot.commands.rating_leaderboard.options.season.description
|
||||||
.description,
|
|
||||||
)
|
)
|
||||||
.setDescriptionLocalizations(
|
.setDescriptionLocalizations(
|
||||||
localizationObject(
|
localizationObject(
|
||||||
(strings) =>
|
(strings) =>
|
||||||
strings.bot.commands.rating_leaderboard.options.season
|
strings.bot.commands.rating_leaderboard.options.season
|
||||||
.description,
|
.description
|
||||||
),
|
)
|
||||||
)
|
)
|
||||||
.setRequired(false)
|
.setRequired(false)
|
||||||
.addChoices(
|
.addChoices(
|
||||||
@@ -124,7 +123,7 @@ export const ratingLeaderboardCommand = new Promise<CommandRegistry>(
|
|||||||
? literals(
|
? literals(
|
||||||
strings.bot.commands.rating_leaderboard.options.season
|
strings.bot.commands.rating_leaderboard.options.season
|
||||||
.choices.current,
|
.choices.current,
|
||||||
[`${number}`],
|
{ season: number }
|
||||||
)
|
)
|
||||||
: `${number}`,
|
: `${number}`,
|
||||||
value: `${number}`,
|
value: `${number}`,
|
||||||
@@ -133,27 +132,27 @@ export const ratingLeaderboardCommand = new Promise<CommandRegistry>(
|
|||||||
(strings) =>
|
(strings) =>
|
||||||
strings.bot.commands.rating_leaderboard.options
|
strings.bot.commands.rating_leaderboard.options
|
||||||
.season.choices.current,
|
.season.choices.current,
|
||||||
[`${number}`],
|
{ season: number }
|
||||||
)
|
)
|
||||||
: undefined,
|
: undefined,
|
||||||
} satisfies APIApplicationCommandOptionChoice<string>;
|
} satisfies APIApplicationCommandOptionChoice<string>;
|
||||||
})
|
})
|
||||||
.reverse(),
|
.reverse()
|
||||||
),
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
resolve({
|
resolve({
|
||||||
command: createLocalizedCommand('rating-leaderboard', [
|
command: createLocalizedCommand("rating-leaderboard", [
|
||||||
{
|
{
|
||||||
subcommand: 'neighbors',
|
subcommand: "neighbors",
|
||||||
modify(option: SlashCommandSubcommandBuilder) {
|
modify(option: SlashCommandSubcommandBuilder) {
|
||||||
option.addStringOption(addUsernameChoices);
|
option.addStringOption(addUsernameChoices);
|
||||||
addOptions(option);
|
addOptions(option);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
subcommand: 'league',
|
subcommand: "league",
|
||||||
modify(option: SlashCommandSubcommandBuilder) {
|
modify(option: SlashCommandSubcommandBuilder) {
|
||||||
option
|
option
|
||||||
.addStringOption((option) => {
|
.addStringOption((option) => {
|
||||||
@@ -161,7 +160,7 @@ export const ratingLeaderboardCommand = new Promise<CommandRegistry>(
|
|||||||
|
|
||||||
return option
|
return option
|
||||||
.setName(
|
.setName(
|
||||||
strings.bot.commands.rating_leaderboard.options.league.name,
|
strings.bot.commands.rating_leaderboard.options.league.name
|
||||||
)
|
)
|
||||||
.setNameLocalizations(
|
.setNameLocalizations(
|
||||||
localizationObject(
|
localizationObject(
|
||||||
@@ -169,19 +168,19 @@ export const ratingLeaderboardCommand = new Promise<CommandRegistry>(
|
|||||||
strings.bot.commands.rating_leaderboard.options.league
|
strings.bot.commands.rating_leaderboard.options.league
|
||||||
.name,
|
.name,
|
||||||
undefined,
|
undefined,
|
||||||
true,
|
true
|
||||||
),
|
)
|
||||||
)
|
)
|
||||||
.setDescription(
|
.setDescription(
|
||||||
strings.bot.commands.rating_leaderboard.options.league
|
strings.bot.commands.rating_leaderboard.options.league
|
||||||
.description,
|
.description
|
||||||
)
|
)
|
||||||
.setDescriptionLocalizations(
|
.setDescriptionLocalizations(
|
||||||
localizationObject(
|
localizationObject(
|
||||||
(strings) =>
|
(strings) =>
|
||||||
strings.bot.commands.rating_leaderboard.options.league
|
strings.bot.commands.rating_leaderboard.options.league
|
||||||
.description,
|
.description
|
||||||
),
|
)
|
||||||
)
|
)
|
||||||
.addChoices(
|
.addChoices(
|
||||||
...LEAGUES.map(
|
...LEAGUES.map(
|
||||||
@@ -195,10 +194,10 @@ export const ratingLeaderboardCommand = new Promise<CommandRegistry>(
|
|||||||
(strings) =>
|
(strings) =>
|
||||||
(
|
(
|
||||||
strings.common.leagues as Record<string, string>
|
strings.common.leagues as Record<string, string>
|
||||||
)[name],
|
)[name]
|
||||||
),
|
),
|
||||||
}) satisfies APIApplicationCommandOptionChoice<string>,
|
}) satisfies APIApplicationCommandOptionChoice<string>
|
||||||
),
|
)
|
||||||
)
|
)
|
||||||
.setRequired(true);
|
.setRequired(true);
|
||||||
})
|
})
|
||||||
@@ -213,10 +212,10 @@ export const ratingLeaderboardCommand = new Promise<CommandRegistry>(
|
|||||||
async handler(interaction) {
|
async handler(interaction) {
|
||||||
const { strings } = translator(interaction.locale);
|
const { strings } = translator(interaction.locale);
|
||||||
const subcommand = interaction.options.getSubcommand(true) as
|
const subcommand = interaction.options.getSubcommand(true) as
|
||||||
| 'league'
|
| "league"
|
||||||
| 'neighbors';
|
| "neighbors";
|
||||||
const limit = interaction.options.getInteger('limit') ?? DEFAULT_LIMIT;
|
const limit = interaction.options.getInteger("limit") ?? DEFAULT_LIMIT;
|
||||||
const seasonOption = interaction.options.getString('season');
|
const seasonOption = interaction.options.getString("season");
|
||||||
const season = seasonOption
|
const season = seasonOption
|
||||||
? parseInt(seasonOption)
|
? parseInt(seasonOption)
|
||||||
: onGoingSeason
|
: onGoingSeason
|
||||||
@@ -232,11 +231,11 @@ export const ratingLeaderboardCommand = new Promise<CommandRegistry>(
|
|||||||
let playerId: number | undefined;
|
let playerId: number | undefined;
|
||||||
let regionRatingInfo: RatingInfo | null;
|
let regionRatingInfo: RatingInfo | null;
|
||||||
|
|
||||||
if (subcommand === 'league') {
|
if (subcommand === "league") {
|
||||||
const leagueIndex = parseInt(
|
const leagueIndex = parseInt(
|
||||||
interaction.options.getString('league')!,
|
interaction.options.getString("league")!
|
||||||
);
|
);
|
||||||
const region = interaction.options.getString('region') as Region;
|
const region = interaction.options.getString("region") as Region;
|
||||||
regionRatingInfo = await (isCurrentSeason
|
regionRatingInfo = await (isCurrentSeason
|
||||||
? getRatingInfo(region)
|
? getRatingInfo(region)
|
||||||
: null);
|
: null);
|
||||||
@@ -259,8 +258,8 @@ export const ratingLeaderboardCommand = new Promise<CommandRegistry>(
|
|||||||
position: player.number,
|
position: player.number,
|
||||||
clan: player.clan_tag,
|
clan: player.clan_tag,
|
||||||
nickname: player.nickname,
|
nickname: player.nickname,
|
||||||
}) satisfies SimplifiedPlayer,
|
}) satisfies SimplifiedPlayer
|
||||||
),
|
)
|
||||||
)
|
)
|
||||||
: await getArchivedRatingLeaderboard(region, season!).then(
|
: await getArchivedRatingLeaderboard(region, season!).then(
|
||||||
async (players) => {
|
async (players) => {
|
||||||
@@ -269,17 +268,17 @@ export const ratingLeaderboardCommand = new Promise<CommandRegistry>(
|
|||||||
? 0
|
? 0
|
||||||
: players.version!.value.entries.findIndex(
|
: players.version!.value.entries.findIndex(
|
||||||
(player) =>
|
(player) =>
|
||||||
player.score < LEAGUES[leagueIndex - 1].minScore,
|
player.score < LEAGUES[leagueIndex - 1].minScore
|
||||||
);
|
);
|
||||||
const lastPlayerIndex = firstPlayerIndex + limit - 1;
|
const lastPlayerIndex = firstPlayerIndex + limit - 1;
|
||||||
const trimmed = players.version!.value.entries.slice(
|
const trimmed = players.version!.value.entries.slice(
|
||||||
firstPlayerIndex,
|
firstPlayerIndex,
|
||||||
lastPlayerIndex + 1,
|
lastPlayerIndex + 1
|
||||||
);
|
);
|
||||||
const clanData = await getClanAccountInfo(
|
const clanData = await getClanAccountInfo(
|
||||||
region,
|
region,
|
||||||
trimmed.map(({ id }) => id),
|
trimmed.map(({ id }) => id),
|
||||||
['clan'],
|
["clan"]
|
||||||
);
|
);
|
||||||
|
|
||||||
return trimmed.map(
|
return trimmed.map(
|
||||||
@@ -294,16 +293,16 @@ export const ratingLeaderboardCommand = new Promise<CommandRegistry>(
|
|||||||
literals(
|
literals(
|
||||||
strings.bot.commands.rating_leaderboard.body
|
strings.bot.commands.rating_leaderboard.body
|
||||||
.deleted_player,
|
.deleted_player,
|
||||||
[`${player.id}`],
|
{ id: player.id }
|
||||||
),
|
),
|
||||||
}) satisfies SimplifiedPlayer,
|
}) satisfies SimplifiedPlayer
|
||||||
);
|
);
|
||||||
},
|
}
|
||||||
);
|
);
|
||||||
const leagueInfo = LEAGUES[leagueIndex];
|
const leagueInfo = LEAGUES[leagueIndex];
|
||||||
archivedLeaderboard = await getArchivedRatingLeaderboard(
|
archivedLeaderboard = await getArchivedRatingLeaderboard(
|
||||||
region,
|
region,
|
||||||
season,
|
season
|
||||||
);
|
);
|
||||||
|
|
||||||
players = result;
|
players = result;
|
||||||
@@ -316,12 +315,12 @@ export const ratingLeaderboardCommand = new Promise<CommandRegistry>(
|
|||||||
? (strings.common.leagues as Record<string, string>)[
|
? (strings.common.leagues as Record<string, string>)[
|
||||||
LEAGUES[leagueInfo.index].name
|
LEAGUES[leagueInfo.index].name
|
||||||
]
|
]
|
||||||
: ''
|
: ""
|
||||||
} - ${strings.common.regions.short[region]}`;
|
} - ${strings.common.regions.short[region]}`;
|
||||||
titleImage = imgur(leagueInfo.icon);
|
titleImage = imgur(leagueInfo.icon);
|
||||||
titleDescription = literals(
|
titleDescription = literals(
|
||||||
strings.bot.commands.rating_leaderboard.body.top_players,
|
strings.bot.commands.rating_leaderboard.body.top_players,
|
||||||
[`${limit}`],
|
{ count: limit }
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
const { region, id } = await resolvePlayerFromCommand(interaction);
|
const { region, id } = await resolvePlayerFromCommand(interaction);
|
||||||
@@ -338,7 +337,7 @@ export const ratingLeaderboardCommand = new Promise<CommandRegistry>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
const accountInfo = await getAccountInfo(region, id);
|
const accountInfo = await getAccountInfo(region, id);
|
||||||
const clan = (await getClanAccountInfo(region, id, ['clan']))?.clan;
|
const clan = (await getClanAccountInfo(region, id, ["clan"]))?.clan;
|
||||||
const neighbors = isCurrentSeason
|
const neighbors = isCurrentSeason
|
||||||
? await getRatingNeighbors(region, id, Math.round(limit / 2)).then(
|
? await getRatingNeighbors(region, id, Math.round(limit / 2)).then(
|
||||||
(players) =>
|
(players) =>
|
||||||
@@ -350,13 +349,13 @@ export const ratingLeaderboardCommand = new Promise<CommandRegistry>(
|
|||||||
score: player.score,
|
score: player.score,
|
||||||
clan: player.clan_tag,
|
clan: player.clan_tag,
|
||||||
nickname: player.nickname,
|
nickname: player.nickname,
|
||||||
}) satisfies SimplifiedPlayer,
|
}) satisfies SimplifiedPlayer
|
||||||
),
|
)
|
||||||
)
|
)
|
||||||
: await getArchivedRatingLeaderboard(region, season!).then(
|
: await getArchivedRatingLeaderboard(region, season!).then(
|
||||||
async (players) => {
|
async (players) => {
|
||||||
const playerIndex = players.version!.value.entries.findIndex(
|
const playerIndex = players.version!.value.entries.findIndex(
|
||||||
(player) => player.id === id,
|
(player) => player.id === id
|
||||||
);
|
);
|
||||||
|
|
||||||
if (playerIndex === -1) {
|
if (playerIndex === -1) {
|
||||||
@@ -364,20 +363,20 @@ export const ratingLeaderboardCommand = new Promise<CommandRegistry>(
|
|||||||
literals(
|
literals(
|
||||||
strings.bot.commands.rating_leaderboard.body
|
strings.bot.commands.rating_leaderboard.body
|
||||||
.no_participation,
|
.no_participation,
|
||||||
[markdownEscape(accountInfo.nickname), `${season}`],
|
{ player: markdownEscape(accountInfo.nickname), season }
|
||||||
),
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const halfRange = Math.round(limit / 2);
|
const halfRange = Math.round(limit / 2);
|
||||||
const trimmed = players.version!.value.entries.slice(
|
const trimmed = players.version!.value.entries.slice(
|
||||||
playerIndex - halfRange,
|
playerIndex - halfRange,
|
||||||
playerIndex + halfRange + 1,
|
playerIndex + halfRange + 1
|
||||||
);
|
);
|
||||||
const clanData = await getClanAccountInfo(
|
const clanData = await getClanAccountInfo(
|
||||||
region,
|
region,
|
||||||
trimmed.map((player) => player.id),
|
trimmed.map((player) => player.id),
|
||||||
['clan'],
|
["clan"]
|
||||||
);
|
);
|
||||||
|
|
||||||
return trimmed.map((player, index) => ({
|
return trimmed.map((player, index) => ({
|
||||||
@@ -389,18 +388,18 @@ export const ratingLeaderboardCommand = new Promise<CommandRegistry>(
|
|||||||
? clanData[index]!.account_name
|
? clanData[index]!.account_name
|
||||||
: `Deleted ${player.id}`,
|
: `Deleted ${player.id}`,
|
||||||
}));
|
}));
|
||||||
},
|
}
|
||||||
);
|
);
|
||||||
archivedLeaderboard = await getArchivedRatingLeaderboard(
|
archivedLeaderboard = await getArchivedRatingLeaderboard(
|
||||||
region,
|
region,
|
||||||
season,
|
season
|
||||||
);
|
);
|
||||||
|
|
||||||
players = neighbors;
|
players = neighbors;
|
||||||
titleImage = clan
|
titleImage = clan
|
||||||
? `https://wotblitz-gc.gcdn.co/icons/clanEmblems1x/clan-icon-v2-${clan.emblem_set_id}.png`
|
? `https://wotblitz-gc.gcdn.co/icons/clanEmblems1x/clan-icon-v2-${clan.emblem_set_id}.png`
|
||||||
: undefined;
|
: undefined;
|
||||||
titleName = neighbors ? accountInfo.nickname : '';
|
titleName = neighbors ? accountInfo.nickname : "";
|
||||||
titleDescription =
|
titleDescription =
|
||||||
strings.bot.commands.rating_leaderboard.body.neighbors;
|
strings.bot.commands.rating_leaderboard.body.neighbors;
|
||||||
playersAfter =
|
playersAfter =
|
||||||
@@ -414,7 +413,7 @@ export const ratingLeaderboardCommand = new Promise<CommandRegistry>(
|
|||||||
const items = players.map((player) => {
|
const items = players.map((player) => {
|
||||||
const midnightIndex =
|
const midnightIndex =
|
||||||
archivedLeaderboard?.version!.value.entries.findIndex(
|
archivedLeaderboard?.version!.value.entries.findIndex(
|
||||||
(item) => item.id === player.id,
|
(item) => item.id === player.id
|
||||||
);
|
);
|
||||||
const midnightScore =
|
const midnightScore =
|
||||||
midnightIndex === undefined
|
midnightIndex === undefined
|
||||||
@@ -453,7 +452,7 @@ export const ratingLeaderboardCommand = new Promise<CommandRegistry>(
|
|||||||
<Leaderboard.Gap
|
<Leaderboard.Gap
|
||||||
message={literals(
|
message={literals(
|
||||||
strings.bot.commands.rating_leaderboard.body.more,
|
strings.bot.commands.rating_leaderboard.body.more,
|
||||||
[`${playersAfter.toLocaleString(interaction.locale)}`],
|
{ count: playersAfter.toLocaleString(interaction.locale) }
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
@@ -465,5 +464,5 @@ export const ratingLeaderboardCommand = new Promise<CommandRegistry>(
|
|||||||
|
|
||||||
autocomplete: autocompleteUsername,
|
autocomplete: autocompleteUsername,
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
);
|
);
|
||||||
@@ -20,7 +20,7 @@ import { blitzStarsTankAverages } from '../core/blitzstars/tankAverages';
|
|||||||
import { buttonLink } from '../core/discord/buttonLink';
|
import { buttonLink } from '../core/discord/buttonLink';
|
||||||
import { createLocalizedCommand } from '../core/discord/createLocalizedCommand';
|
import { createLocalizedCommand } from '../core/discord/createLocalizedCommand';
|
||||||
import { translator } from '../core/localization/translator';
|
import { translator } from '../core/localization/translator';
|
||||||
import { CommandRegistry } from '../events/interactionCreate';
|
import { type CommandRegistry } from '../events/interactionCreate';
|
||||||
import { theme } from '../stitches.config';
|
import { theme } from '../stitches.config';
|
||||||
|
|
||||||
type WotInspectorReplaySubmission =
|
type WotInspectorReplaySubmission =
|
||||||
|
|||||||
@@ -8,31 +8,31 @@ import {
|
|||||||
TANK_ICONS,
|
TANK_ICONS,
|
||||||
TankType,
|
TankType,
|
||||||
TIER_ROMAN_NUMERALS,
|
TIER_ROMAN_NUMERALS,
|
||||||
} from '@blitzkit/core';
|
} from "@blitzkit/core";
|
||||||
import { literals } from '@blitzkit/i18n';
|
import { literals } from "@blitzkit/i18n";
|
||||||
import { escapeMarkdown, Locale } from 'discord.js';
|
import { escapeMarkdown, Locale } from "discord.js";
|
||||||
import { CommandWrapper } from '../components/CommandWrapper';
|
import { CommandWrapper } from "../components/CommandWrapper";
|
||||||
import { TitleBar } from '../components/TitleBar';
|
import { TitleBar } from "../components/TitleBar";
|
||||||
import { resolveTankId } from '../core/blitz/resolveTankId';
|
import { resolveTankId } from "../core/blitz/resolveTankId";
|
||||||
import { buildTechTreeLine } from '../core/blitzkit/buildTechTreeLine';
|
import { buildTechTreeLine } from "../core/blitzkit/buildTechTreeLine";
|
||||||
import { iconPng } from '../core/blitzkit/iconPng';
|
import { iconPng } from "../core/blitzkit/iconPng";
|
||||||
import { tankDefinitions } from '../core/blitzkit/nonBlockingPromises';
|
import { tankDefinitions } from "../core/blitzkit/nonBlockingPromises";
|
||||||
import { resolveAncestry } from '../core/blitzkit/resolveAncestry';
|
import { resolveAncestry } from "../core/blitzkit/resolveAncestry";
|
||||||
import { tankIconPng } from '../core/blitzkit/tankIconPng';
|
import { tankIconPng } from "../core/blitzkit/tankIconPng";
|
||||||
import { addUsernameChoices } from '../core/discord/addUsernameChoices';
|
import { addUsernameChoices } from "../core/discord/addUsernameChoices";
|
||||||
import { autocompleteTanks } from '../core/discord/autocompleteTanks';
|
import { autocompleteTanks } from "../core/discord/autocompleteTanks";
|
||||||
import { createLocalizedCommand } from '../core/discord/createLocalizedCommand';
|
import { createLocalizedCommand } from "../core/discord/createLocalizedCommand";
|
||||||
import { localizationObject } from '../core/discord/localizationObject';
|
import { localizationObject } from "../core/discord/localizationObject";
|
||||||
import { resolvePlayerFromCommand } from '../core/discord/resolvePlayerFromCommand';
|
import { resolvePlayerFromCommand } from "../core/discord/resolvePlayerFromCommand";
|
||||||
import { translator } from '../core/localization/translator';
|
import { translator } from "../core/localization/translator";
|
||||||
import { CommandRegistry } from '../events/interactionCreate';
|
import { type CommandRegistry } from "../events/interactionCreate";
|
||||||
import { theme } from '../stitches.config';
|
import { theme } from "../stitches.config";
|
||||||
|
|
||||||
export const researchCommand = new Promise<CommandRegistry>((resolve) => {
|
export const researchCommand = new Promise<CommandRegistry>((resolve) => {
|
||||||
const { strings } = translator(Locale.EnglishUS);
|
const { strings } = translator(Locale.EnglishUS);
|
||||||
|
|
||||||
resolve({
|
resolve({
|
||||||
command: createLocalizedCommand('research')
|
command: createLocalizedCommand("research")
|
||||||
.addStringOption((option) =>
|
.addStringOption((option) =>
|
||||||
option
|
option
|
||||||
.setName(strings.bot.commands.research.options.target_tank.name)
|
.setName(strings.bot.commands.research.options.target_tank.name)
|
||||||
@@ -41,20 +41,20 @@ export const researchCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
(strings) =>
|
(strings) =>
|
||||||
strings.bot.commands.research.options.target_tank.name,
|
strings.bot.commands.research.options.target_tank.name,
|
||||||
undefined,
|
undefined,
|
||||||
true,
|
true
|
||||||
),
|
)
|
||||||
)
|
)
|
||||||
.setDescription(
|
.setDescription(
|
||||||
strings.bot.commands.research.options.target_tank.description,
|
strings.bot.commands.research.options.target_tank.description
|
||||||
)
|
)
|
||||||
.setDescriptionLocalizations(
|
.setDescriptionLocalizations(
|
||||||
localizationObject(
|
localizationObject(
|
||||||
(strings) =>
|
(strings) =>
|
||||||
strings.bot.commands.research.options.target_tank.description,
|
strings.bot.commands.research.options.target_tank.description
|
||||||
),
|
)
|
||||||
)
|
)
|
||||||
.setAutocomplete(true)
|
.setAutocomplete(true)
|
||||||
.setRequired(true),
|
.setRequired(true)
|
||||||
)
|
)
|
||||||
.addStringOption((option) =>
|
.addStringOption((option) =>
|
||||||
option
|
option
|
||||||
@@ -64,20 +64,20 @@ export const researchCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
(strings) =>
|
(strings) =>
|
||||||
strings.bot.commands.research.options.starting_tank.name,
|
strings.bot.commands.research.options.starting_tank.name,
|
||||||
undefined,
|
undefined,
|
||||||
true,
|
true
|
||||||
),
|
)
|
||||||
)
|
)
|
||||||
.setDescription(
|
.setDescription(
|
||||||
strings.bot.commands.research.options.starting_tank.description,
|
strings.bot.commands.research.options.starting_tank.description
|
||||||
)
|
)
|
||||||
.setDescriptionLocalizations(
|
.setDescriptionLocalizations(
|
||||||
localizationObject(
|
localizationObject(
|
||||||
(strings) =>
|
(strings) =>
|
||||||
strings.bot.commands.research.options.starting_tank.description,
|
strings.bot.commands.research.options.starting_tank.description
|
||||||
),
|
)
|
||||||
)
|
)
|
||||||
.setAutocomplete(true)
|
.setAutocomplete(true)
|
||||||
.setRequired(false),
|
.setRequired(false)
|
||||||
)
|
)
|
||||||
.addStringOption(addUsernameChoices),
|
.addStringOption(addUsernameChoices),
|
||||||
|
|
||||||
@@ -85,11 +85,11 @@ export const researchCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
const { strings, unwrap } = translator(interaction.locale);
|
const { strings, unwrap } = translator(interaction.locale);
|
||||||
const awaitedTankDefinitions = await tankDefinitions;
|
const awaitedTankDefinitions = await tankDefinitions;
|
||||||
const targetTankId = await resolveTankId(
|
const targetTankId = await resolveTankId(
|
||||||
interaction.options.getString('target-tank', true),
|
interaction.options.getString("target-tank", true),
|
||||||
interaction.locale,
|
interaction.locale,
|
||||||
true,
|
true
|
||||||
);
|
);
|
||||||
const startingTankRaw = interaction.options.getString('starting-tank');
|
const startingTankRaw = interaction.options.getString("starting-tank");
|
||||||
const targetTank = awaitedTankDefinitions.tanks[targetTankId];
|
const targetTank = awaitedTankDefinitions.tanks[targetTankId];
|
||||||
const { id, region } = await resolvePlayerFromCommand(interaction);
|
const { id, region } = await resolvePlayerFromCommand(interaction);
|
||||||
let startingTankId: number;
|
let startingTankId: number;
|
||||||
@@ -99,46 +99,45 @@ export const researchCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
startingTankId = await resolveTankId(
|
startingTankId = await resolveTankId(
|
||||||
startingTankRaw,
|
startingTankRaw,
|
||||||
interaction.locale,
|
interaction.locale,
|
||||||
true,
|
true
|
||||||
);
|
);
|
||||||
|
|
||||||
if (targetTankId === startingTankId) {
|
if (targetTankId === startingTankId) {
|
||||||
return literals(
|
return literals(
|
||||||
strings.bot.commands.research.errors.start_end_equal,
|
strings.bot.commands.research.errors.start_end_equal,
|
||||||
[escapeMarkdown(unwrap(targetTank.name))],
|
{ tank: escapeMarkdown(unwrap(targetTank.name)) }
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const startingTank = awaitedTankDefinitions.tanks[startingTankId];
|
const startingTank = awaitedTankDefinitions.tanks[startingTankId];
|
||||||
|
|
||||||
if (startingTank.tier > targetTank.tier) {
|
if (startingTank.tier > targetTank.tier) {
|
||||||
return literals(strings.bot.commands.research.errors.unordered, [
|
return literals(strings.bot.commands.research.errors.unordered, {
|
||||||
escapeMarkdown(unwrap(startingTank.name)),
|
tank_1: escapeMarkdown(unwrap(startingTank.name)),
|
||||||
escapeMarkdown(unwrap(targetTank.name)),
|
tank_2: escapeMarkdown(unwrap(targetTank.name)),
|
||||||
escapeMarkdown(unwrap(targetTank.name)),
|
});
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!targetTankAncestry.includes(startingTankId)) {
|
if (!targetTankAncestry.includes(startingTankId)) {
|
||||||
return literals(
|
return literals(
|
||||||
strings.bot.commands.research.errors.tanks_not_on_line,
|
strings.bot.commands.research.errors.tanks_not_on_line,
|
||||||
[
|
{
|
||||||
escapeMarkdown(unwrap(targetTank.name)),
|
tank_1: escapeMarkdown(unwrap(targetTank.name)),
|
||||||
escapeMarkdown(unwrap(startingTank.name)),
|
tank_2: escapeMarkdown(unwrap(startingTank.name)),
|
||||||
],
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (targetTank.type !== TankType.RESEARCHABLE) {
|
if (targetTank.type !== TankType.RESEARCHABLE) {
|
||||||
return literals(strings.bot.commands.research.errors.non_tech_tree, [
|
return literals(strings.bot.commands.research.errors.non_tech_tree, {
|
||||||
escapeMarkdown(unwrap(targetTank.name)),
|
tank: escapeMarkdown(unwrap(targetTank.name)),
|
||||||
]);
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (targetTank.tier === 1) {
|
if (targetTank.tier === 1) {
|
||||||
return literals(strings.bot.commands.research.errors.tier_1, [
|
return literals(strings.bot.commands.research.errors.tier_1, {
|
||||||
escapeMarkdown(unwrap(targetTank.name)),
|
tank: escapeMarkdown(unwrap(targetTank.name)),
|
||||||
]);
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const tankStats = await getTankStats(region, id);
|
const tankStats = await getTankStats(region, id);
|
||||||
@@ -150,18 +149,18 @@ export const researchCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
if (tankStats.some(({ tank_id }) => tank_id === targetTankId)) {
|
if (tankStats.some(({ tank_id }) => tank_id === targetTankId)) {
|
||||||
return literals(
|
return literals(
|
||||||
strings.bot.commands.research.errors.already_researched,
|
strings.bot.commands.research.errors.already_researched,
|
||||||
[escapeMarkdown(unwrap(targetTank.name))],
|
{ tank: escapeMarkdown(unwrap(targetTank.name)) }
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const foundAncestor = targetTankAncestry.find(
|
const foundAncestor = targetTankAncestry.find(
|
||||||
(id) =>
|
(id) =>
|
||||||
awaitedTankDefinitions.tanks[id].tier === 1 ||
|
awaitedTankDefinitions.tanks[id].tier === 1 ||
|
||||||
tankStats.some(({ tank_id }) => tank_id === id),
|
tankStats.some(({ tank_id }) => tank_id === id)
|
||||||
);
|
);
|
||||||
|
|
||||||
if (foundAncestor === undefined) {
|
if (foundAncestor === undefined) {
|
||||||
throw new Error('No first owned tech tree found.');
|
throw new Error("No first owned tech tree found.");
|
||||||
}
|
}
|
||||||
|
|
||||||
startingTankId = foundAncestor;
|
startingTankId = foundAncestor;
|
||||||
@@ -169,12 +168,12 @@ export const researchCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
|
|
||||||
const techTreeLine = await buildTechTreeLine(
|
const techTreeLine = await buildTechTreeLine(
|
||||||
startingTankId,
|
startingTankId,
|
||||||
targetTankId,
|
targetTankId
|
||||||
);
|
);
|
||||||
|
|
||||||
const line = [...techTreeLine, startingTankId].reverse();
|
const line = [...techTreeLine, startingTankId].reverse();
|
||||||
const { nickname } = await getAccountInfo(region, id);
|
const { nickname } = await getAccountInfo(region, id);
|
||||||
const clan = (await getClanAccountInfo(region, id, ['clan']))?.clan;
|
const clan = (await getClanAccountInfo(region, id, ["clan"]))?.clan;
|
||||||
const clanImage = clan ? emblemURL(clan.emblem_set_id) : undefined;
|
const clanImage = clan ? emblemURL(clan.emblem_set_id) : undefined;
|
||||||
const costs = await Promise.all(
|
const costs = await Promise.all(
|
||||||
line.map(async (id) => {
|
line.map(async (id) => {
|
||||||
@@ -187,18 +186,18 @@ export const researchCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
tank.turrets.forEach((turret) => {
|
tank.turrets.forEach((turret) => {
|
||||||
if (
|
if (
|
||||||
turret.research_cost !== undefined &&
|
turret.research_cost !== undefined &&
|
||||||
typeof turret.research_cost.research_cost_type!.value === 'number'
|
typeof turret.research_cost.research_cost_type!.value === "number"
|
||||||
) {
|
) {
|
||||||
turretXps.set(
|
turretXps.set(
|
||||||
turret.id,
|
turret.id,
|
||||||
turret.research_cost.research_cost_type!.value,
|
turret.research_cost.research_cost_type!.value
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
turret.guns.forEach((gun) => {
|
turret.guns.forEach((gun) => {
|
||||||
if (
|
if (
|
||||||
gun.research_cost !== undefined &&
|
gun.research_cost !== undefined &&
|
||||||
typeof gun.research_cost.research_cost_type!.value === 'number'
|
typeof gun.research_cost.research_cost_type!.value === "number"
|
||||||
) {
|
) {
|
||||||
gunXps.set(gun.id, gun.research_cost.research_cost_type!.value);
|
gunXps.set(gun.id, gun.research_cost.research_cost_type!.value);
|
||||||
}
|
}
|
||||||
@@ -208,11 +207,11 @@ export const researchCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
tank.engines.forEach((engine) => {
|
tank.engines.forEach((engine) => {
|
||||||
if (
|
if (
|
||||||
engine.research_cost !== undefined &&
|
engine.research_cost !== undefined &&
|
||||||
typeof engine.research_cost.research_cost_type!.value === 'number'
|
typeof engine.research_cost.research_cost_type!.value === "number"
|
||||||
) {
|
) {
|
||||||
engineXps.set(
|
engineXps.set(
|
||||||
engine.id,
|
engine.id,
|
||||||
engine.research_cost.research_cost_type!.value,
|
engine.research_cost.research_cost_type!.value
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -220,11 +219,11 @@ export const researchCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
tank.tracks.forEach((track) => {
|
tank.tracks.forEach((track) => {
|
||||||
if (
|
if (
|
||||||
track.research_cost !== undefined &&
|
track.research_cost !== undefined &&
|
||||||
typeof track.research_cost.research_cost_type!.value === 'number'
|
typeof track.research_cost.research_cost_type!.value === "number"
|
||||||
) {
|
) {
|
||||||
trackXps.set(
|
trackXps.set(
|
||||||
track.id,
|
track.id,
|
||||||
track.research_cost.research_cost_type!.value,
|
track.research_cost.research_cost_type!.value
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -249,10 +248,10 @@ export const researchCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
purchase: tank.price.value,
|
purchase: tank.price.value,
|
||||||
equipment: equipmentPriceMatrix[tank.tier].reduce(
|
equipment: equipmentPriceMatrix[tank.tier].reduce(
|
||||||
(a, b) => a + 3 * b,
|
(a, b) => a + 3 * b,
|
||||||
0,
|
0
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
}),
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
const image = (
|
const image = (
|
||||||
@@ -267,14 +266,14 @@ export const researchCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
|
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
flexDirection: 'column',
|
flexDirection: "column",
|
||||||
gap: 8,
|
gap: 8,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
borderRadius: 4,
|
borderRadius: 4,
|
||||||
backgroundColor: theme.colors.appBackground2,
|
backgroundColor: theme.colors.appBackground2,
|
||||||
border: theme.borderStyles.subtle,
|
border: theme.borderStyles.subtle,
|
||||||
@@ -285,10 +284,10 @@ export const researchCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
flex: 1,
|
flex: 1,
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
alignItems: 'center',
|
alignItems: "center",
|
||||||
justifyContent: 'center',
|
justifyContent: "center",
|
||||||
position: 'relative',
|
position: "relative",
|
||||||
right: 24,
|
right: 24,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@@ -304,23 +303,23 @@ export const researchCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
flex: 1,
|
flex: 1,
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
flexDirection: 'column',
|
flexDirection: "column",
|
||||||
justifyContent: 'center',
|
justifyContent: "center",
|
||||||
gap: 8,
|
gap: 8,
|
||||||
padding: '16px 0',
|
padding: "16px 0",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
gap: 4,
|
gap: 4,
|
||||||
alignItems: 'center',
|
alignItems: "center",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<img
|
<img
|
||||||
alt="XP icon"
|
alt="XP icon"
|
||||||
src={await iconPng(asset('icons/currencies/xp.webp'))}
|
src={await iconPng(asset("icons/currencies/xp.webp"))}
|
||||||
width={16}
|
width={16}
|
||||||
height={16}
|
height={16}
|
||||||
/>
|
/>
|
||||||
@@ -330,7 +329,7 @@ export const researchCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
color: theme.colors.textHighContrast,
|
color: theme.colors.textHighContrast,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Experience:{' '}
|
Experience:{" "}
|
||||||
{costs
|
{costs
|
||||||
.reduce((a, b) => a + (b.research ?? 0) + b.upgrades, 0)
|
.reduce((a, b) => a + (b.research ?? 0) + b.upgrades, 0)
|
||||||
.toLocaleString(interaction.locale)}
|
.toLocaleString(interaction.locale)}
|
||||||
@@ -339,14 +338,14 @@ export const researchCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
|
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
gap: 4,
|
gap: 4,
|
||||||
alignItems: 'center',
|
alignItems: "center",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<img
|
<img
|
||||||
alt="Silver icon"
|
alt="Silver icon"
|
||||||
src={await iconPng(asset('icons/currencies/silver.webp'))}
|
src={await iconPng(asset("icons/currencies/silver.webp"))}
|
||||||
width={16}
|
width={16}
|
||||||
height={16}
|
height={16}
|
||||||
/>
|
/>
|
||||||
@@ -356,7 +355,7 @@ export const researchCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
color: theme.colors.textHighContrast,
|
color: theme.colors.textHighContrast,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Purchase:{' '}
|
Purchase:{" "}
|
||||||
{costs
|
{costs
|
||||||
.reduce((a, b) => a + b.purchase, 0)
|
.reduce((a, b) => a + b.purchase, 0)
|
||||||
.toLocaleString(interaction.locale)}
|
.toLocaleString(interaction.locale)}
|
||||||
@@ -365,14 +364,14 @@ export const researchCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
|
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
gap: 4,
|
gap: 4,
|
||||||
alignItems: 'center',
|
alignItems: "center",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<img
|
<img
|
||||||
alt="Silver icon"
|
alt="Silver icon"
|
||||||
src={await iconPng(asset('icons/currencies/silver.webp'))}
|
src={await iconPng(asset("icons/currencies/silver.webp"))}
|
||||||
width={16}
|
width={16}
|
||||||
height={16}
|
height={16}
|
||||||
/>
|
/>
|
||||||
@@ -382,7 +381,7 @@ export const researchCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
color: theme.colors.textHighContrast,
|
color: theme.colors.textHighContrast,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Equipment:{' '}
|
Equipment:{" "}
|
||||||
{costs
|
{costs
|
||||||
.reduce((a, b) => a + b.equipment, 0)
|
.reduce((a, b) => a + b.equipment, 0)
|
||||||
.toLocaleString(interaction.locale)}
|
.toLocaleString(interaction.locale)}
|
||||||
@@ -399,7 +398,7 @@ export const researchCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
<div
|
<div
|
||||||
key={id}
|
key={id}
|
||||||
style={{
|
style={{
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
borderRadius: 4,
|
borderRadius: 4,
|
||||||
backgroundColor: theme.colors.appBackground2,
|
backgroundColor: theme.colors.appBackground2,
|
||||||
border: theme.borderStyles.subtle,
|
border: theme.borderStyles.subtle,
|
||||||
@@ -408,9 +407,9 @@ export const researchCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
width: 48,
|
width: 48,
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
alignItems: 'center',
|
alignItems: "center",
|
||||||
justifyContent: 'center',
|
justifyContent: "center",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
@@ -426,9 +425,9 @@ export const researchCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
flex: 1,
|
flex: 1,
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
position: 'relative',
|
position: "relative",
|
||||||
right: '5%',
|
right: "5%",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<img
|
<img
|
||||||
@@ -437,23 +436,23 @@ export const researchCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
style={{
|
style={{
|
||||||
height: 100,
|
height: 100,
|
||||||
width: 100,
|
width: 100,
|
||||||
objectFit: 'contain',
|
objectFit: "contain",
|
||||||
position: 'absolute',
|
position: "absolute",
|
||||||
left: '25%',
|
left: "25%",
|
||||||
top: 0,
|
top: 0,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
gap: 4,
|
gap: 4,
|
||||||
alignItems: 'center',
|
alignItems: "center",
|
||||||
justifyContent: 'center',
|
justifyContent: "center",
|
||||||
position: 'absolute',
|
position: "absolute",
|
||||||
bottom: 8,
|
bottom: 8,
|
||||||
left: '50%',
|
left: "50%",
|
||||||
transform: 'translateX(-50%)',
|
transform: "translateX(-50%)",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<img
|
<img
|
||||||
@@ -476,23 +475,23 @@ export const researchCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
flex: 1,
|
flex: 1,
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
flexDirection: 'column',
|
flexDirection: "column",
|
||||||
justifyContent: 'center',
|
justifyContent: "center",
|
||||||
gap: 8,
|
gap: 8,
|
||||||
padding: '16px 0',
|
padding: "16px 0",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
gap: 4,
|
gap: 4,
|
||||||
alignItems: 'center',
|
alignItems: "center",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<img
|
<img
|
||||||
alt="XP icon"
|
alt="XP icon"
|
||||||
src={await iconPng(asset('icons/currencies/xp.webp'))}
|
src={await iconPng(asset("icons/currencies/xp.webp"))}
|
||||||
width={16}
|
width={16}
|
||||||
height={16}
|
height={16}
|
||||||
/>
|
/>
|
||||||
@@ -504,11 +503,11 @@ export const researchCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
>
|
>
|
||||||
{literals(
|
{literals(
|
||||||
strings.bot.commands.research.body.research,
|
strings.bot.commands.research.body.research,
|
||||||
[
|
{
|
||||||
`${costs[index].research?.toLocaleString(
|
cost: costs[index].research?.toLocaleString(
|
||||||
interaction.locale,
|
interaction.locale
|
||||||
)}`,
|
),
|
||||||
],
|
}
|
||||||
)}
|
)}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
@@ -516,15 +515,15 @@ export const researchCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
{costs[index].upgrades > 0 && (
|
{costs[index].upgrades > 0 && (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
gap: 4,
|
gap: 4,
|
||||||
alignItems: 'center',
|
alignItems: "center",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<img
|
<img
|
||||||
alt="Free XP icon"
|
alt="Free XP icon"
|
||||||
src={await iconPng(
|
src={await iconPng(
|
||||||
asset('icons/currencies/free-xp.webp'),
|
asset("icons/currencies/free-xp.webp")
|
||||||
)}
|
)}
|
||||||
width={16}
|
width={16}
|
||||||
height={16}
|
height={16}
|
||||||
@@ -537,7 +536,7 @@ export const researchCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
>
|
>
|
||||||
{literals(
|
{literals(
|
||||||
strings.bot.commands.research.body.upgrades,
|
strings.bot.commands.research.body.upgrades,
|
||||||
[costs[index].upgrades.toLocaleString()],
|
{ cost: costs[index].upgrades.toLocaleString() }
|
||||||
)}
|
)}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
@@ -545,15 +544,15 @@ export const researchCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
|
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
gap: 4,
|
gap: 4,
|
||||||
alignItems: 'center',
|
alignItems: "center",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<img
|
<img
|
||||||
alt="Silver icon"
|
alt="Silver icon"
|
||||||
src={await iconPng(
|
src={await iconPng(
|
||||||
asset('icons/currencies/silver.webp'),
|
asset("icons/currencies/silver.webp")
|
||||||
)}
|
)}
|
||||||
width={16}
|
width={16}
|
||||||
height={16}
|
height={16}
|
||||||
@@ -566,26 +565,26 @@ export const researchCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
>
|
>
|
||||||
{literals(
|
{literals(
|
||||||
strings.bot.commands.research.body.purchase,
|
strings.bot.commands.research.body.purchase,
|
||||||
[
|
{
|
||||||
costs[index].purchase.toLocaleString(
|
cost: costs[index].purchase.toLocaleString(
|
||||||
interaction.locale,
|
interaction.locale
|
||||||
),
|
),
|
||||||
],
|
}
|
||||||
)}
|
)}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
gap: 4,
|
gap: 4,
|
||||||
alignItems: 'center',
|
alignItems: "center",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<img
|
<img
|
||||||
alt="Silver icon"
|
alt="Silver icon"
|
||||||
src={await iconPng(
|
src={await iconPng(
|
||||||
asset('icons/currencies/silver.webp'),
|
asset("icons/currencies/silver.webp")
|
||||||
)}
|
)}
|
||||||
width={16}
|
width={16}
|
||||||
height={16}
|
height={16}
|
||||||
@@ -598,18 +597,18 @@ export const researchCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
>
|
>
|
||||||
{literals(
|
{literals(
|
||||||
strings.bot.commands.research.body.equipment,
|
strings.bot.commands.research.body.equipment,
|
||||||
[
|
{
|
||||||
costs[index].equipment.toLocaleString(
|
cost: costs[index].equipment.toLocaleString(
|
||||||
interaction.locale,
|
interaction.locale
|
||||||
),
|
),
|
||||||
],
|
}
|
||||||
)}
|
)}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}),
|
})
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</CommandWrapper>
|
</CommandWrapper>
|
||||||
@@ -621,7 +620,7 @@ export const researchCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
},
|
},
|
||||||
|
|
||||||
autocomplete(interaction) {
|
autocomplete(interaction) {
|
||||||
autocompleteTanks(interaction, true, ['target-tank', 'starting-tank']);
|
autocompleteTanks(interaction, true, ["target-tank", "starting-tank"]);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -1,23 +1,23 @@
|
|||||||
import { ClanList, fetchBlitz, Region } from '@blitzkit/core';
|
import { type ClanList, fetchBlitz, type Region } from "@blitzkit/core";
|
||||||
import { literals } from '@blitzkit/i18n';
|
import { literals } from "@blitzkit/i18n";
|
||||||
import { Locale } from 'discord.js';
|
import { Locale } from "discord.js";
|
||||||
import markdownEscape from 'markdown-escape';
|
import markdownEscape from "markdown-escape";
|
||||||
import { addClanChoices } from '../core/discord/addClanChoices';
|
import { addClanChoices } from "../core/discord/addClanChoices";
|
||||||
import { addRegionChoices } from '../core/discord/addRegionChoices';
|
import { addRegionChoices } from "../core/discord/addRegionChoices";
|
||||||
import { createLocalizedCommand } from '../core/discord/createLocalizedCommand';
|
import { createLocalizedCommand } from "../core/discord/createLocalizedCommand";
|
||||||
import { embedInfo } from '../core/discord/embedInfo';
|
import { embedInfo } from "../core/discord/embedInfo";
|
||||||
import { localizationObject } from '../core/discord/localizationObject';
|
import { localizationObject } from "../core/discord/localizationObject";
|
||||||
import { translator } from '../core/localization/translator';
|
import { translator } from "../core/localization/translator";
|
||||||
import { CommandRegistry } from '../events/interactionCreate';
|
import type { CommandRegistry } from "../events/interactionCreate";
|
||||||
|
|
||||||
const DEFAULT_LIMIT = 25;
|
const DEFAULT_LIMIT = 25;
|
||||||
|
|
||||||
export const searchClansCommand = new Promise<CommandRegistry>((resolve) => {
|
export const searchClansCommand = new Promise<CommandRegistry>((resolve) => {
|
||||||
resolve({
|
resolve({
|
||||||
command: createLocalizedCommand('search-clans')
|
command: createLocalizedCommand("search-clans")
|
||||||
.addStringOption(addRegionChoices)
|
.addStringOption(addRegionChoices)
|
||||||
.addStringOption((option) =>
|
.addStringOption((option) =>
|
||||||
addClanChoices(option).setAutocomplete(false),
|
addClanChoices(option).setAutocomplete(false)
|
||||||
)
|
)
|
||||||
.addIntegerOption((option) => {
|
.addIntegerOption((option) => {
|
||||||
const { strings } = translator(Locale.EnglishUS);
|
const { strings } = translator(Locale.EnglishUS);
|
||||||
@@ -28,21 +28,21 @@ export const searchClansCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
localizationObject(
|
localizationObject(
|
||||||
(strings) => strings.bot.commands.search_clans.options.limit.name,
|
(strings) => strings.bot.commands.search_clans.options.limit.name,
|
||||||
undefined,
|
undefined,
|
||||||
true,
|
true
|
||||||
),
|
)
|
||||||
)
|
)
|
||||||
.setDescription(
|
.setDescription(
|
||||||
literals(
|
literals(
|
||||||
strings.bot.commands.search_clans.options.limit.description,
|
strings.bot.commands.search_clans.options.limit.description,
|
||||||
[`${DEFAULT_LIMIT}`],
|
{ limit: DEFAULT_LIMIT }
|
||||||
),
|
)
|
||||||
)
|
)
|
||||||
.setDescriptionLocalizations(
|
.setDescriptionLocalizations(
|
||||||
localizationObject(
|
localizationObject(
|
||||||
(strings) =>
|
(strings) =>
|
||||||
strings.bot.commands.search_clans.options.limit.description,
|
strings.bot.commands.search_clans.options.limit.description,
|
||||||
[`${DEFAULT_LIMIT}`],
|
{ limit: DEFAULT_LIMIT }
|
||||||
),
|
)
|
||||||
)
|
)
|
||||||
.setMinValue(1)
|
.setMinValue(1)
|
||||||
.setMaxValue(100);
|
.setMaxValue(100);
|
||||||
@@ -50,24 +50,24 @@ export const searchClansCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
|
|
||||||
async handler(interaction) {
|
async handler(interaction) {
|
||||||
const { strings } = translator(interaction.locale);
|
const { strings } = translator(interaction.locale);
|
||||||
const region = interaction.options.getString('region') as Region;
|
const region = interaction.options.getString("region") as Region;
|
||||||
const clan = interaction.options.getString('clan')!;
|
const clan = interaction.options.getString("clan")!;
|
||||||
const limit = interaction.options.getInteger('limit') ?? DEFAULT_LIMIT;
|
const limit = interaction.options.getInteger("limit") ?? DEFAULT_LIMIT;
|
||||||
const clanList = await fetchBlitz<ClanList>(region, 'clans/list', {
|
const clanList = await fetchBlitz<ClanList>(region, "clans/list", {
|
||||||
search: clan,
|
search: clan,
|
||||||
limit,
|
limit,
|
||||||
});
|
});
|
||||||
|
|
||||||
return embedInfo(
|
return embedInfo(
|
||||||
literals(strings.bot.commands.search_clans.body.title, [
|
literals(strings.bot.commands.search_clans.body.title, {
|
||||||
markdownEscape(clan),
|
search: markdownEscape(clan),
|
||||||
strings.common.regions.normal[region],
|
region: strings.common.regions.normal[region],
|
||||||
]),
|
}),
|
||||||
clanList.length === 0
|
clanList.length === 0
|
||||||
? strings.bot.commands.search_clans.body.no_results
|
? strings.bot.commands.search_clans.body.no_results
|
||||||
: `\`\`\`\n${clanList
|
: `\`\`\`\n${clanList
|
||||||
.map((clan) => `${clan.name} [${clan.tag}]`)
|
.map((clan) => `${clan.name} [${clan.tag}]`)
|
||||||
.join('\n')}\n\`\`\``,
|
.join("\n")}\n\`\`\``
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,19 +1,19 @@
|
|||||||
import {
|
import {
|
||||||
AccountList,
|
type AccountList,
|
||||||
fetchBlitz,
|
fetchBlitz,
|
||||||
Region,
|
type Region,
|
||||||
usernamePattern,
|
usernamePattern,
|
||||||
} from '@blitzkit/core';
|
} from "@blitzkit/core";
|
||||||
import { literals } from '@blitzkit/i18n';
|
import { literals } from "@blitzkit/i18n";
|
||||||
import { Locale } from 'discord.js';
|
import { Locale } from "discord.js";
|
||||||
import markdownEscape from 'markdown-escape';
|
import markdownEscape from "markdown-escape";
|
||||||
import { addRegionChoices } from '../core/discord/addRegionChoices';
|
import { addRegionChoices } from "../core/discord/addRegionChoices";
|
||||||
import { addUsernameChoices } from '../core/discord/addUsernameChoices';
|
import { addUsernameChoices } from "../core/discord/addUsernameChoices";
|
||||||
import { createLocalizedCommand } from '../core/discord/createLocalizedCommand';
|
import { createLocalizedCommand } from "../core/discord/createLocalizedCommand";
|
||||||
import { embedInfo } from '../core/discord/embedInfo';
|
import { embedInfo } from "../core/discord/embedInfo";
|
||||||
import { localizationObject } from '../core/discord/localizationObject';
|
import { localizationObject } from "../core/discord/localizationObject";
|
||||||
import { translator } from '../core/localization/translator';
|
import { translator } from "../core/localization/translator";
|
||||||
import { CommandRegistry } from '../events/interactionCreate';
|
import type { CommandRegistry } from "../events/interactionCreate";
|
||||||
|
|
||||||
const DEFAULT_LIMIT = 25;
|
const DEFAULT_LIMIT = 25;
|
||||||
|
|
||||||
@@ -21,10 +21,10 @@ export const searchPlayersCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
const { strings } = translator(Locale.EnglishUS);
|
const { strings } = translator(Locale.EnglishUS);
|
||||||
|
|
||||||
resolve({
|
resolve({
|
||||||
command: createLocalizedCommand('search-players')
|
command: createLocalizedCommand("search-players")
|
||||||
.addStringOption(addRegionChoices)
|
.addStringOption(addRegionChoices)
|
||||||
.addStringOption((option) =>
|
.addStringOption((option) =>
|
||||||
addUsernameChoices(option).setAutocomplete(false).setRequired(true),
|
addUsernameChoices(option).setAutocomplete(false).setRequired(true)
|
||||||
)
|
)
|
||||||
.addIntegerOption((option) =>
|
.addIntegerOption((option) =>
|
||||||
option
|
option
|
||||||
@@ -34,49 +34,49 @@ export const searchPlayersCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
(strings) =>
|
(strings) =>
|
||||||
strings.bot.commands.search_players.options.limit.name,
|
strings.bot.commands.search_players.options.limit.name,
|
||||||
undefined,
|
undefined,
|
||||||
true,
|
true
|
||||||
),
|
)
|
||||||
)
|
)
|
||||||
.setDescription(
|
.setDescription(
|
||||||
literals(
|
literals(
|
||||||
strings.bot.commands.search_players.options.limit.description,
|
strings.bot.commands.search_players.options.limit.description,
|
||||||
[`${DEFAULT_LIMIT}`],
|
{ limit: DEFAULT_LIMIT }
|
||||||
),
|
)
|
||||||
)
|
)
|
||||||
.setDescriptionLocalizations(
|
.setDescriptionLocalizations(
|
||||||
localizationObject(
|
localizationObject(
|
||||||
(strings) =>
|
(strings) =>
|
||||||
strings.bot.commands.search_players.options.limit.description,
|
strings.bot.commands.search_players.options.limit.description,
|
||||||
[`${DEFAULT_LIMIT}`],
|
{ limit: DEFAULT_LIMIT }
|
||||||
),
|
)
|
||||||
)
|
)
|
||||||
.setMinValue(1)
|
.setMinValue(1)
|
||||||
.setMaxValue(100),
|
.setMaxValue(100)
|
||||||
),
|
),
|
||||||
|
|
||||||
async handler(interaction) {
|
async handler(interaction) {
|
||||||
const { strings } = translator(interaction.locale);
|
const { strings } = translator(interaction.locale);
|
||||||
const region = interaction.options.getString('region') as Region;
|
const region = interaction.options.getString("region") as Region;
|
||||||
const name = interaction.options.getString('username')!;
|
const name = interaction.options.getString("username")!;
|
||||||
const limit = interaction.options.getInteger('limit') ?? 25;
|
const limit = interaction.options.getInteger("limit") ?? 25;
|
||||||
const trimmedSearch = name.trim();
|
const trimmedSearch = name.trim();
|
||||||
const players = usernamePattern.test(trimmedSearch)
|
const players = usernamePattern.test(trimmedSearch)
|
||||||
? await fetchBlitz<AccountList>(region, 'account/list', {
|
? await fetchBlitz<AccountList>(region, "account/list", {
|
||||||
search: trimmedSearch,
|
search: trimmedSearch,
|
||||||
limit,
|
limit,
|
||||||
})
|
})
|
||||||
: [];
|
: [];
|
||||||
|
|
||||||
return embedInfo(
|
return embedInfo(
|
||||||
literals(strings.bot.commands.search_players.body.title, [
|
literals(strings.bot.commands.search_players.body.title, {
|
||||||
markdownEscape(trimmedSearch),
|
search: markdownEscape(trimmedSearch),
|
||||||
strings.common.regions.normal[region],
|
region: strings.common.regions.normal[region],
|
||||||
]),
|
}),
|
||||||
`\`\`\`${
|
`\`\`\`${
|
||||||
players.length === 0
|
players.length === 0
|
||||||
? strings.bot.commands.search_players.body.no_results
|
? strings.bot.commands.search_players.body.no_results
|
||||||
: players.map((player) => player.nickname).join('\n')
|
: players.map((player) => player.nickname).join("\n")
|
||||||
}\`\`\``,
|
}\`\`\``
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,50 +1,50 @@
|
|||||||
import { emblemURL, getAccountInfo, getClanAccountInfo } from '@blitzkit/core';
|
import { emblemURL, getAccountInfo, getClanAccountInfo } from "@blitzkit/core";
|
||||||
import { Locale } from 'discord.js';
|
import { Locale } from "discord.js";
|
||||||
import { AllStatsOverview } from '../components/AllStatsOverview';
|
import { AllStatsOverview } from "../components/AllStatsOverview";
|
||||||
import { CommandWrapper } from '../components/CommandWrapper';
|
import { CommandWrapper } from "../components/CommandWrapper";
|
||||||
import { NoData } from '../components/NoData';
|
import { NoData } from "../components/NoData";
|
||||||
import { TitleBar } from '../components/TitleBar';
|
import { TitleBar } from "../components/TitleBar";
|
||||||
import { filtersToDescription } from '../core/blitzkit/filtersToDescription';
|
import { filtersToDescription } from "../core/blitzkit/filtersToDescription";
|
||||||
import { filterStats, StatFilters } from '../core/blitzstars/filterStats';
|
import { filterStats, type StatFilters } from "../core/blitzstars/filterStats";
|
||||||
import { getBlitzStarsLinkButton } from '../core/blitzstars/getBlitzStarsLinkButton';
|
import { getBlitzStarsLinkButton } from "../core/blitzstars/getBlitzStarsLinkButton";
|
||||||
import { getStatsInPeriod } from '../core/blitzstars/getStatsInPeriod';
|
import { getStatsInPeriod } from "../core/blitzstars/getStatsInPeriod";
|
||||||
import { addPeriodicFilterOptions } from '../core/discord/addPeriodicFilterOptions';
|
import { addPeriodicFilterOptions } from "../core/discord/addPeriodicFilterOptions";
|
||||||
import { addUsernameChoices } from '../core/discord/addUsernameChoices';
|
import { addUsernameChoices } from "../core/discord/addUsernameChoices";
|
||||||
import { autocompleteTanks } from '../core/discord/autocompleteTanks';
|
import { autocompleteTanks } from "../core/discord/autocompleteTanks";
|
||||||
import { autocompleteUsername } from '../core/discord/autocompleteUsername';
|
import { autocompleteUsername } from "../core/discord/autocompleteUsername";
|
||||||
import { buttonRefresh } from '../core/discord/buttonRefresh';
|
import { buttonRefresh } from "../core/discord/buttonRefresh";
|
||||||
import { commandToURL } from '../core/discord/commandToURL';
|
import { commandToURL } from "../core/discord/commandToURL";
|
||||||
import { createLocalizedCommand } from '../core/discord/createLocalizedCommand';
|
import { createLocalizedCommand } from "../core/discord/createLocalizedCommand";
|
||||||
import { getCustomPeriodParams } from '../core/discord/getCustomPeriodParams';
|
import { getCustomPeriodParams } from "../core/discord/getCustomPeriodParams";
|
||||||
import { getFiltersFromButton } from '../core/discord/getFiltersFromButton';
|
import { getFiltersFromButton } from "../core/discord/getFiltersFromButton";
|
||||||
import { getFiltersFromCommand } from '../core/discord/getFiltersFromCommand';
|
import { getFiltersFromCommand } from "../core/discord/getFiltersFromCommand";
|
||||||
import { resolvePeriodFromButton } from '../core/discord/resolvePeriodFromButton';
|
import { resolvePeriodFromButton } from "../core/discord/resolvePeriodFromButton";
|
||||||
import {
|
import {
|
||||||
ResolvedPeriod,
|
type ResolvedPeriod,
|
||||||
resolvePeriodFromCommand,
|
resolvePeriodFromCommand,
|
||||||
} from '../core/discord/resolvePeriodFromCommand';
|
} from "../core/discord/resolvePeriodFromCommand";
|
||||||
import { resolvePlayerFromButton } from '../core/discord/resolvePlayerFromButton';
|
import { resolvePlayerFromButton } from "../core/discord/resolvePlayerFromButton";
|
||||||
import {
|
import {
|
||||||
ResolvedPlayer,
|
type ResolvedPlayer,
|
||||||
resolvePlayerFromCommand,
|
resolvePlayerFromCommand,
|
||||||
} from '../core/discord/resolvePlayerFromCommand';
|
} from "../core/discord/resolvePlayerFromCommand";
|
||||||
import { CommandRegistry } from '../events/interactionCreate';
|
import type { CommandRegistry } from "../events/interactionCreate";
|
||||||
|
|
||||||
async function render(
|
async function render(
|
||||||
{ region, id }: ResolvedPlayer,
|
{ region, id }: ResolvedPlayer,
|
||||||
{ start, end, name }: ResolvedPeriod,
|
{ start, end, name }: ResolvedPeriod,
|
||||||
filters: StatFilters,
|
filters: StatFilters,
|
||||||
locale: Locale,
|
locale: Locale
|
||||||
) {
|
) {
|
||||||
const { nickname } = await getAccountInfo(region, id);
|
const { nickname } = await getAccountInfo(region, id);
|
||||||
const clan = (await getClanAccountInfo(region, id, ['clan']))?.clan;
|
const clan = (await getClanAccountInfo(region, id, ["clan"]))?.clan;
|
||||||
const clanImage = clan ? emblemURL(clan.emblem_set_id) : undefined;
|
const clanImage = clan ? emblemURL(clan.emblem_set_id) : undefined;
|
||||||
const diffedTankStats = await getStatsInPeriod(
|
const diffedTankStats = await getStatsInPeriod(
|
||||||
region,
|
region,
|
||||||
id,
|
id,
|
||||||
start,
|
start,
|
||||||
end,
|
end,
|
||||||
locale,
|
locale
|
||||||
);
|
);
|
||||||
const { stats, supplementary } = await filterStats(diffedTankStats, filters);
|
const { stats, supplementary } = await filterStats(diffedTankStats, filters);
|
||||||
const filterDescriptions = await filtersToDescription(filters, locale);
|
const filterDescriptions = await filtersToDescription(filters, locale);
|
||||||
@@ -72,8 +72,8 @@ async function render(
|
|||||||
export const statsCommand = new Promise<CommandRegistry>(async (resolve) => {
|
export const statsCommand = new Promise<CommandRegistry>(async (resolve) => {
|
||||||
resolve({
|
resolve({
|
||||||
command: await addPeriodicFilterOptions(
|
command: await addPeriodicFilterOptions(
|
||||||
createLocalizedCommand('stats'),
|
createLocalizedCommand("stats"),
|
||||||
(option) => option.addStringOption(addUsernameChoices),
|
(option) => option.addStringOption(addUsernameChoices)
|
||||||
),
|
),
|
||||||
|
|
||||||
async handler(interaction) {
|
async handler(interaction) {
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import { resolvePeriodFromButton } from '../core/discord/resolvePeriodFromButton
|
|||||||
import { resolvePeriodFromCommand } from '../core/discord/resolvePeriodFromCommand';
|
import { resolvePeriodFromCommand } from '../core/discord/resolvePeriodFromCommand';
|
||||||
import { resolvePlayerFromButton } from '../core/discord/resolvePlayerFromButton';
|
import { resolvePlayerFromButton } from '../core/discord/resolvePlayerFromButton';
|
||||||
import { resolvePlayerFromCommand } from '../core/discord/resolvePlayerFromCommand';
|
import { resolvePlayerFromCommand } from '../core/discord/resolvePlayerFromCommand';
|
||||||
import { CommandRegistry } from '../events/interactionCreate';
|
import { type CommandRegistry } from '../events/interactionCreate';
|
||||||
import { renderBreakdown } from './breakdown/render';
|
import { renderBreakdown } from './breakdown/render';
|
||||||
|
|
||||||
export const todayCommand = new Promise<CommandRegistry>(async (resolve) => {
|
export const todayCommand = new Promise<CommandRegistry>(async (resolve) => {
|
||||||
|
|||||||
+10
-10
@@ -1,8 +1,8 @@
|
|||||||
import { ComponentProps } from 'react';
|
import { type ComponentProps } from "react";
|
||||||
|
|
||||||
export interface GlowProps extends ComponentProps<'div'> {
|
export interface GlowProps extends ComponentProps<"div"> {
|
||||||
color: string;
|
color: string;
|
||||||
direction?: 'default' | 'reverse';
|
direction?: "default" | "reverse";
|
||||||
rotation?: number;
|
rotation?: number;
|
||||||
startOpacity?: number;
|
startOpacity?: number;
|
||||||
endOpacity?: number;
|
endOpacity?: number;
|
||||||
@@ -12,7 +12,7 @@ const width = 16;
|
|||||||
|
|
||||||
export function Glow({
|
export function Glow({
|
||||||
color,
|
color,
|
||||||
direction = 'default',
|
direction = "default",
|
||||||
rotation = 0,
|
rotation = 0,
|
||||||
style,
|
style,
|
||||||
startOpacity = 0,
|
startOpacity = 0,
|
||||||
@@ -21,20 +21,20 @@ export function Glow({
|
|||||||
}: GlowProps) {
|
}: GlowProps) {
|
||||||
const color1 = `${color}${Math.round(endOpacity * 255)
|
const color1 = `${color}${Math.round(endOpacity * 255)
|
||||||
.toString(16)
|
.toString(16)
|
||||||
.padStart(2, '0')}`;
|
.padStart(2, "0")}`;
|
||||||
const color2 = `${color}${Math.round(startOpacity * 255)
|
const color2 = `${color}${Math.round(startOpacity * 255)
|
||||||
.toString(16)
|
.toString(16)
|
||||||
.padStart(2, '0')}`;
|
.padStart(2, "0")}`;
|
||||||
const background = `linear-gradient(${
|
const background = `linear-gradient(${
|
||||||
direction === 'default' ? 0 : 180
|
direction === "default" ? 0 : 180
|
||||||
}deg, ${color1} 0%, ${color2} 100%)`;
|
}deg, ${color1} 0%, ${color2} 100%)`;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
alignItems: direction === 'default' ? 'flex-end' : 'flex-start',
|
alignItems: direction === "default" ? "flex-end" : "flex-start",
|
||||||
justifyContent: 'center',
|
justifyContent: "center",
|
||||||
transform: `rotate(${rotation}deg)`,
|
transform: `rotate(${rotation}deg)`,
|
||||||
...style,
|
...style,
|
||||||
}}
|
}}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import {
|
import {
|
||||||
getWN8Percentile,
|
getWN8Percentile,
|
||||||
Percentile,
|
Percentile,
|
||||||
SupplementaryStats,
|
type SupplementaryStats,
|
||||||
} from '@blitzkit/core';
|
} from '@blitzkit/core';
|
||||||
import { Locale } from 'discord.js';
|
import { Locale } from 'discord.js';
|
||||||
import { translator } from '../../core/localization/translator';
|
import { translator } from '../../core/localization/translator';
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { ReactNode } from 'react';
|
import { type ReactNode } from "react";
|
||||||
|
|
||||||
interface RootProps {
|
interface RootProps {
|
||||||
children: ReactNode;
|
children: ReactNode;
|
||||||
@@ -8,7 +8,7 @@ export function Root({ children }: RootProps) {
|
|||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className="session-tracker-root"
|
className="session-tracker-root"
|
||||||
style={{ display: 'flex', flexDirection: 'column', gap: 8 }}
|
style={{ display: "flex", flexDirection: "column", gap: 8 }}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -6,8 +6,8 @@ import {
|
|||||||
} from '@blitzkit/core';
|
} from '@blitzkit/core';
|
||||||
import { createColors } from 'bepaint';
|
import { createColors } from 'bepaint';
|
||||||
import {
|
import {
|
||||||
AccentColor,
|
type AccentColor,
|
||||||
GrayColor,
|
type GrayColor,
|
||||||
PALETTES,
|
PALETTES,
|
||||||
} from '../../../core/radix/radixColors';
|
} from '../../../core/radix/radixColors';
|
||||||
import { RowStat } from './RowStat';
|
import { RowStat } from './RowStat';
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
import { Percentile } from '@blitzkit/core';
|
import { Percentile } from "@blitzkit/core";
|
||||||
import { createColors } from 'bepaint';
|
import { createColors } from "bepaint";
|
||||||
import {
|
import {
|
||||||
AccentColor,
|
type AccentColor,
|
||||||
GrayColor,
|
type GrayColor,
|
||||||
PALETTES,
|
PALETTES,
|
||||||
} from '../../../core/radix/radixColors';
|
} from "../../../core/radix/radixColors";
|
||||||
import { PercentileIndicator } from '../../PercentileIndicator';
|
import { PercentileIndicator } from "../../PercentileIndicator";
|
||||||
|
|
||||||
interface RowStatProps {
|
interface RowStatProps {
|
||||||
name: string;
|
name: string;
|
||||||
@@ -22,7 +22,7 @@ export function RowStat({
|
|||||||
delta,
|
delta,
|
||||||
percentile,
|
percentile,
|
||||||
minimized = false,
|
minimized = false,
|
||||||
color = 'slate',
|
color = "slate",
|
||||||
}: RowStatProps) {
|
}: RowStatProps) {
|
||||||
const theme = createColors(PALETTES[`${color}Dark`]);
|
const theme = createColors(PALETTES[`${color}Dark`]);
|
||||||
|
|
||||||
@@ -30,29 +30,29 @@ export function RowStat({
|
|||||||
<div
|
<div
|
||||||
className="session-tracker-row-stat"
|
className="session-tracker-row-stat"
|
||||||
style={{
|
style={{
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
flexDirection: 'column',
|
flexDirection: "column",
|
||||||
gap: 4,
|
gap: 4,
|
||||||
alignItems: 'center',
|
alignItems: "center",
|
||||||
justifyContent: 'center',
|
justifyContent: "center",
|
||||||
flex: 1,
|
flex: 1,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
gap: 4,
|
gap: 4,
|
||||||
alignItems: 'center',
|
alignItems: "center",
|
||||||
justifyContent: 'center',
|
justifyContent: "center",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{percentile === undefined && delta !== undefined && delta !== 0 && (
|
{percentile === undefined && delta !== undefined && delta !== 0 && (
|
||||||
<img
|
<img
|
||||||
alt={delta > 0 ? 'Increase' : 'Decrease'}
|
alt={delta > 0 ? "Increase" : "Decrease"}
|
||||||
src={
|
src={
|
||||||
(delta ?? 0) > 0
|
(delta ?? 0) > 0
|
||||||
? 'https://i.imgur.com/qbjiXa1.png'
|
? "https://i.imgur.com/qbjiXa1.png"
|
||||||
: 'https://i.imgur.com/3uyNhun.png'
|
: "https://i.imgur.com/3uyNhun.png"
|
||||||
}
|
}
|
||||||
style={{ width: 12, height: 12 }}
|
style={{ width: 12, height: 12 }}
|
||||||
/>
|
/>
|
||||||
@@ -66,7 +66,7 @@ export function RowStat({
|
|||||||
color: theme.textHighContrast,
|
color: theme.textHighContrast,
|
||||||
fontWeight: 700,
|
fontWeight: 700,
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
textAlign: 'center',
|
textAlign: "center",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{value}
|
{value}
|
||||||
@@ -77,7 +77,7 @@ export function RowStat({
|
|||||||
<span
|
<span
|
||||||
style={{
|
style={{
|
||||||
color: theme.textLowContrast,
|
color: theme.textLowContrast,
|
||||||
textAlign: 'center',
|
textAlign: "center",
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { ReactNode } from 'react';
|
import { type ReactNode } from "react";
|
||||||
import { theme } from '../stitches.config';
|
import { theme } from "../stitches.config";
|
||||||
|
|
||||||
interface CommandWrapperProps {
|
interface CommandWrapperProps {
|
||||||
children: ReactNode;
|
children: ReactNode;
|
||||||
@@ -10,14 +10,14 @@ export function CommandWrapper({ children, fat }: CommandWrapperProps) {
|
|||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
flexDirection: 'column',
|
flexDirection: "column",
|
||||||
padding: `16px ${fat ? 0 : 16}px`,
|
padding: `16px ${fat ? 0 : 16}px`,
|
||||||
gap: 16,
|
gap: 16,
|
||||||
width: '100%',
|
width: "100%",
|
||||||
color: theme.colors.textHighContrast,
|
color: theme.colors.textHighContrast,
|
||||||
backgroundColor: theme.colors.appBackground1,
|
backgroundColor: theme.colors.appBackground1,
|
||||||
position: 'relative',
|
position: "relative",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import {
|
import {
|
||||||
BlitzStats,
|
type BlitzStats,
|
||||||
getWN8Percentile,
|
getWN8Percentile,
|
||||||
isNumber,
|
isNumber,
|
||||||
SupplementaryStats,
|
type SupplementaryStats,
|
||||||
} from '@blitzkit/core';
|
} from '@blitzkit/core';
|
||||||
import { Locale } from 'discord.js';
|
import { Locale } from 'discord.js';
|
||||||
import { translator } from '../../core/localization/translator';
|
import { translator } from '../../core/localization/translator';
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { GenericStat } from '..';
|
import { type GenericStat } from "..";
|
||||||
import { GenericStatsRow } from './GenericStatsRow';
|
import { GenericStatsRow } from "./GenericStatsRow";
|
||||||
|
|
||||||
interface GenericStatsColumnProps {
|
interface GenericStatsColumnProps {
|
||||||
stats: GenericStat[];
|
stats: GenericStat[];
|
||||||
@@ -7,7 +7,7 @@ interface GenericStatsColumnProps {
|
|||||||
|
|
||||||
export function GenericStatsColumn({ stats }: GenericStatsColumnProps) {
|
export function GenericStatsColumn({ stats }: GenericStatsColumnProps) {
|
||||||
return (
|
return (
|
||||||
<div style={{ flex: 1, display: 'flex', flexDirection: 'column', gap: 8 }}>
|
<div style={{ flex: 1, display: "flex", flexDirection: "column", gap: 8 }}>
|
||||||
{stats.map((stat) => (
|
{stats.map((stat) => (
|
||||||
<GenericStatsRow key={stat[0]} stat={stat} />
|
<GenericStatsRow key={stat[0]} stat={stat} />
|
||||||
))}
|
))}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { GenericStat } from '..';
|
import { type GenericStat } from "..";
|
||||||
import { theme } from '../../../stitches.config';
|
import { theme } from "../../../stitches.config";
|
||||||
import { PercentileIndicator } from '../../PercentileIndicator';
|
import { PercentileIndicator } from "../../PercentileIndicator";
|
||||||
|
|
||||||
interface GenericStatsRowProps {
|
interface GenericStatsRowProps {
|
||||||
stat: GenericStat;
|
stat: GenericStat;
|
||||||
@@ -10,18 +10,18 @@ export function GenericStatsRow({ stat }: GenericStatsRowProps) {
|
|||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
justifyContent: 'space-between',
|
justifyContent: "space-between",
|
||||||
alignItems: 'center',
|
alignItems: "center",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
style={{
|
style={{
|
||||||
color: theme.colors.textLowContrast,
|
color: theme.colors.textLowContrast,
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
whiteSpace: 'nowrap',
|
whiteSpace: "nowrap",
|
||||||
maxWidth: 128,
|
maxWidth: 128,
|
||||||
overflow: 'hidden',
|
overflow: "hidden",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{stat[0]}
|
{stat[0]}
|
||||||
@@ -32,9 +32,9 @@ export function GenericStatsRow({ stat }: GenericStatsRowProps) {
|
|||||||
color: theme.colors.textHighContrast,
|
color: theme.colors.textHighContrast,
|
||||||
fontWeight: 700,
|
fontWeight: 700,
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
alignItems: 'center',
|
alignItems: "center",
|
||||||
justifyContent: 'center',
|
justifyContent: "center",
|
||||||
gap: 4,
|
gap: 4,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { times } from 'lodash-es';
|
import { times } from 'lodash-es';
|
||||||
import { theme } from '../../../../stitches.config';
|
import { theme } from '../../../../stitches.config';
|
||||||
import { MarginInputProps } from '../Root';
|
import { type MarginInputProps } from '../Root';
|
||||||
import { MarginOrientation } from './constants';
|
import { MarginOrientation } from './constants';
|
||||||
|
|
||||||
interface MarginProps extends MarginInputProps {
|
interface MarginProps extends MarginInputProps {
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import { times } from 'lodash-es';
|
import { times } from "lodash-es";
|
||||||
import { ReactNode } from 'react';
|
import { type ReactNode } from "react";
|
||||||
import { theme } from '../../../../stitches.config';
|
import { theme } from "../../../../stitches.config";
|
||||||
import { Margin } from '../Margin';
|
import { Margin } from "../Margin";
|
||||||
import { MarginOrientation } from '../Margin/constants';
|
import { MarginOrientation } from "../Margin/constants";
|
||||||
import { GRAPH_HEIGHT, GRAPH_WIDTH } from './constants';
|
import { GRAPH_HEIGHT, GRAPH_WIDTH } from "./constants";
|
||||||
|
|
||||||
export interface MarginInputProps {
|
export interface MarginInputProps {
|
||||||
min: number;
|
min: number;
|
||||||
@@ -32,12 +32,12 @@ export function Root({
|
|||||||
xTitle,
|
xTitle,
|
||||||
}: RootProps) {
|
}: RootProps) {
|
||||||
return (
|
return (
|
||||||
<div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
|
<div style={{ display: "flex", flexDirection: "column", gap: 16 }}>
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
paddingLeft: 64,
|
paddingLeft: 64,
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
justifyContent: 'space-between',
|
justifyContent: "space-between",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<span style={{ fontSize: 16, color: theme.colors.textHighContrast }}>
|
<span style={{ fontSize: 16, color: theme.colors.textHighContrast }}>
|
||||||
@@ -48,7 +48,7 @@ export function Root({
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div style={{ display: 'flex', gap: 16 }}>
|
<div style={{ display: "flex", gap: 16 }}>
|
||||||
{verticalMargin && (
|
{verticalMargin && (
|
||||||
<Margin {...verticalMargin} verticalSeparations={separations} />
|
<Margin {...verticalMargin} verticalSeparations={separations} />
|
||||||
)}
|
)}
|
||||||
@@ -94,9 +94,9 @@ export function Root({
|
|||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
paddingLeft: 64,
|
paddingLeft: 64,
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
alignItems: 'center',
|
alignItems: "center",
|
||||||
justifyContent: 'center',
|
justifyContent: "center",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<span style={{ fontSize: 16, color: theme.colors.textLowContrast }}>
|
<span style={{ fontSize: 16, color: theme.colors.textLowContrast }}>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { ComponentProps } from 'react';
|
import { type ComponentProps } from "react";
|
||||||
import { theme } from '../../../stitches.config';
|
import { theme } from "../../../stitches.config";
|
||||||
|
|
||||||
interface ItemProps extends ComponentProps<'div'> {
|
interface ItemProps extends ComponentProps<"div"> {
|
||||||
position: number;
|
position: number;
|
||||||
deltaPosition?: number;
|
deltaPosition?: number;
|
||||||
score?: number;
|
score?: number;
|
||||||
@@ -25,15 +25,15 @@ export function Item({
|
|||||||
<div
|
<div
|
||||||
{...props}
|
{...props}
|
||||||
style={{
|
style={{
|
||||||
cursor: 'pointer',
|
cursor: "pointer",
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
padding: 8,
|
padding: 8,
|
||||||
backgroundColor: highlight
|
backgroundColor: highlight
|
||||||
? theme.colors.componentInteractive_blue
|
? theme.colors.componentInteractive_blue
|
||||||
: theme.colors.componentInteractive,
|
: theme.colors.componentInteractive,
|
||||||
borderRadius: 4,
|
borderRadius: 4,
|
||||||
alignItems: 'center',
|
alignItems: "center",
|
||||||
justifyContent: 'center',
|
justifyContent: "center",
|
||||||
gap: 8,
|
gap: 8,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@@ -50,9 +50,9 @@ export function Item({
|
|||||||
|
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
alignItems: 'center',
|
alignItems: "center",
|
||||||
justifyContent: 'center',
|
justifyContent: "center",
|
||||||
gap: 4,
|
gap: 4,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@@ -83,22 +83,22 @@ export function Item({
|
|||||||
{deltaPosition !== undefined && deltaPosition !== 0 && (
|
{deltaPosition !== undefined && deltaPosition !== 0 && (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
alignItems: 'center',
|
alignItems: "center",
|
||||||
justifyContent: 'center',
|
justifyContent: "center",
|
||||||
gap: 4,
|
gap: 4,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<img
|
<img
|
||||||
alt={deltaPosition > 0 ? 'Increase' : 'Decrease'}
|
alt={deltaPosition > 0 ? "Increase" : "Decrease"}
|
||||||
style={{
|
style={{
|
||||||
width: 8,
|
width: 8,
|
||||||
height: 8,
|
height: 8,
|
||||||
}}
|
}}
|
||||||
src={
|
src={
|
||||||
deltaPosition > 0
|
deltaPosition > 0
|
||||||
? 'https://i.imgur.com/qbjiXa1.png'
|
? "https://i.imgur.com/qbjiXa1.png"
|
||||||
: 'https://i.imgur.com/3uyNhun.png'
|
: "https://i.imgur.com/3uyNhun.png"
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<span
|
<span
|
||||||
@@ -119,11 +119,11 @@ export function Item({
|
|||||||
|
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
gap: 4,
|
gap: 4,
|
||||||
alignItems: 'center',
|
alignItems: "center",
|
||||||
width: 96,
|
width: 96,
|
||||||
justifyContent: 'flex-end',
|
justifyContent: "flex-end",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{deltaScore !== 0 && deltaScore !== undefined && (
|
{deltaScore !== 0 && deltaScore !== undefined && (
|
||||||
@@ -140,15 +140,15 @@ export function Item({
|
|||||||
)}
|
)}
|
||||||
{deltaScore !== 0 && deltaScore !== undefined && (
|
{deltaScore !== 0 && deltaScore !== undefined && (
|
||||||
<img
|
<img
|
||||||
alt={deltaScore > 0 ? 'Increase' : 'Decrease'}
|
alt={deltaScore > 0 ? "Increase" : "Decrease"}
|
||||||
style={{
|
style={{
|
||||||
width: 8,
|
width: 8,
|
||||||
height: 8,
|
height: 8,
|
||||||
}}
|
}}
|
||||||
src={
|
src={
|
||||||
deltaScore > 0
|
deltaScore > 0
|
||||||
? 'https://i.imgur.com/qbjiXa1.png'
|
? "https://i.imgur.com/qbjiXa1.png"
|
||||||
: 'https://i.imgur.com/3uyNhun.png'
|
: "https://i.imgur.com/3uyNhun.png"
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { ReactNode } from 'react';
|
import { type ReactNode } from 'react';
|
||||||
|
|
||||||
interface RootProps {
|
interface RootProps {
|
||||||
children: ReactNode;
|
children: ReactNode;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { ReactNode } from 'react';
|
import { type ReactNode } from 'react';
|
||||||
|
|
||||||
interface ColumnProps {
|
interface ColumnProps {
|
||||||
children: ReactNode;
|
children: ReactNode;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { ReactNode } from 'react';
|
import { type ReactNode } from "react";
|
||||||
|
|
||||||
interface RootProps {
|
interface RootProps {
|
||||||
children: ReactNode;
|
children: ReactNode;
|
||||||
@@ -8,8 +8,8 @@ export function Root({ children }: RootProps) {
|
|||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
flexDirection: 'column',
|
flexDirection: "column",
|
||||||
gap: 16,
|
gap: 16,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { ReactNode } from 'react';
|
import { type ReactNode } from "react";
|
||||||
|
|
||||||
interface RowProps {
|
interface RowProps {
|
||||||
children: ReactNode;
|
children: ReactNode;
|
||||||
@@ -8,7 +8,7 @@ export function Row({ children }: RowProps) {
|
|||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
gap: 8,
|
gap: 8,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { TierWeightsRecord } from '@blitzkit/core';
|
import type { TierWeightsRecord } from "@blitzkit/core";
|
||||||
import { theme } from '../stitches.config';
|
import { theme } from "../stitches.config";
|
||||||
|
|
||||||
interface TierWeightsProps {
|
interface TierWeightsProps {
|
||||||
weights: TierWeightsRecord;
|
weights: TierWeightsRecord;
|
||||||
@@ -7,7 +7,7 @@ interface TierWeightsProps {
|
|||||||
|
|
||||||
export function TierWeights({ weights }: TierWeightsProps) {
|
export function TierWeights({ weights }: TierWeightsProps) {
|
||||||
return (
|
return (
|
||||||
<div style={{ display: 'flex', gap: 8 }}>
|
<div style={{ display: "flex", gap: 8 }}>
|
||||||
{Object.entries(weights).map(([tier, weight]) => (
|
{Object.entries(weights).map(([tier, weight]) => (
|
||||||
<div
|
<div
|
||||||
key={tier}
|
key={tier}
|
||||||
@@ -15,11 +15,11 @@ export function TierWeights({ weights }: TierWeightsProps) {
|
|||||||
backgroundColor: theme.colors.appBackground1_light,
|
backgroundColor: theme.colors.appBackground1_light,
|
||||||
flex: weight,
|
flex: weight,
|
||||||
color: theme.colors.textHighContrast_light,
|
color: theme.colors.textHighContrast_light,
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
alignItems: 'center',
|
alignItems: "center",
|
||||||
justifyContent: 'center',
|
justifyContent: "center",
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
overflow: 'hidden',
|
overflow: "hidden",
|
||||||
borderRadius: 8,
|
borderRadius: 8,
|
||||||
minWidth: 16,
|
minWidth: 16,
|
||||||
}}
|
}}
|
||||||
|
|||||||
@@ -1,33 +1,33 @@
|
|||||||
import { SEARCH_KEYS } from '@blitzkit/core';
|
import { SEARCH_KEYS } from "@blitzkit/core";
|
||||||
import { literals } from '@blitzkit/i18n';
|
import { literals } from "@blitzkit/i18n";
|
||||||
import { Locale } from 'discord.js';
|
import { Locale } from "discord.js";
|
||||||
import { go } from 'fuzzysort';
|
import { go } from "fuzzysort";
|
||||||
import markdownEscape from 'markdown-escape';
|
import markdownEscape from "markdown-escape";
|
||||||
import { tankDefinitions, tankNames } from '../blitzkit/nonBlockingPromises';
|
import { tankDefinitions, tankNames } from "../blitzkit/nonBlockingPromises";
|
||||||
import { UserError } from '../blitzkit/userError';
|
import { UserError } from "../blitzkit/userError";
|
||||||
import { tankNamesTechTreeOnly } from '../discord/autocompleteTanks';
|
import { tankNamesTechTreeOnly } from "../discord/autocompleteTanks";
|
||||||
import { translator } from '../localization/translator';
|
import { translator } from "../localization/translator";
|
||||||
|
|
||||||
export async function resolveTankId(
|
export async function resolveTankId(
|
||||||
tank: string | number,
|
tank: string | number,
|
||||||
locale: Locale,
|
locale: Locale,
|
||||||
techTreeOnly = false,
|
techTreeOnly = false
|
||||||
) {
|
) {
|
||||||
const { strings } = translator(locale);
|
const { strings } = translator(locale);
|
||||||
const number = typeof tank === 'string' ? Number(tank) : tank;
|
const number = typeof tank === "string" ? Number(tank) : tank;
|
||||||
|
|
||||||
if (Number.isNaN(number)) {
|
if (Number.isNaN(number)) {
|
||||||
const searchResult = go(
|
const searchResult = go(
|
||||||
`${tank}`,
|
`${tank}`,
|
||||||
await (techTreeOnly ? tankNamesTechTreeOnly : tankNames),
|
await (techTreeOnly ? tankNamesTechTreeOnly : tankNames),
|
||||||
{ keys: SEARCH_KEYS, limit: 1 },
|
{ keys: SEARCH_KEYS, limit: 1 }
|
||||||
);
|
);
|
||||||
|
|
||||||
if (searchResult.length === 0) {
|
if (searchResult.length === 0) {
|
||||||
throw new UserError(
|
throw new UserError(
|
||||||
literals(strings.bot.common.errors.tank_name_not_found, [
|
literals(strings.bot.common.errors.tank_name_not_found, {
|
||||||
markdownEscape(`${tank}`),
|
search: markdownEscape(`${tank}`),
|
||||||
]),
|
})
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return searchResult[0].obj.id;
|
return searchResult[0].obj.id;
|
||||||
@@ -39,7 +39,9 @@ export async function resolveTankId(
|
|||||||
return number;
|
return number;
|
||||||
} else {
|
} else {
|
||||||
throw new UserError(
|
throw new UserError(
|
||||||
literals(strings.bot.common.errors.tank_id_not_found, [`${number}`]),
|
literals(strings.bot.common.errors.tank_id_not_found, {
|
||||||
|
search: number,
|
||||||
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
import { fetchTankDefinitions, TIER_ROMAN_NUMERALS } from '@blitzkit/core';
|
import { fetchTankDefinitions, TIER_ROMAN_NUMERALS } from "@blitzkit/core";
|
||||||
import { literals } from '@blitzkit/i18n';
|
import { literals } from "@blitzkit/i18n";
|
||||||
import { Locale } from 'discord.js';
|
import { Locale } from "discord.js";
|
||||||
import { StatFilters } from '../blitzstars/filterStats';
|
import { type StatFilters } from "../blitzstars/filterStats";
|
||||||
import { translator } from '../localization/translator';
|
import { translator } from "../localization/translator";
|
||||||
|
|
||||||
export async function filtersToDescription(
|
export async function filtersToDescription(
|
||||||
{ nation, tier, type, class: tankClass, tank }: StatFilters,
|
{ nation, tier, type, class: tankClass, tank }: StatFilters,
|
||||||
locale: Locale,
|
locale: Locale
|
||||||
) {
|
) {
|
||||||
const { strings, bkLocale } = translator(locale);
|
const { strings, bkLocale } = translator(locale);
|
||||||
const awaitedTankDefinitions = await fetchTankDefinitions();
|
const awaitedTankDefinitions = await fetchTankDefinitions();
|
||||||
@@ -18,11 +18,13 @@ export async function filtersToDescription(
|
|||||||
info.push((strings.common.nations as Record<string, string>)[nation]);
|
info.push((strings.common.nations as Record<string, string>)[nation]);
|
||||||
if (tier) {
|
if (tier) {
|
||||||
info.push(
|
info.push(
|
||||||
literals(strings.bot.common.filters.tier, [TIER_ROMAN_NUMERALS[tier]]),
|
literals(strings.bot.common.filters.tier, {
|
||||||
|
tier: TIER_ROMAN_NUMERALS[tier],
|
||||||
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (tankClass) info.push(strings.common.tank_class_short[tankClass]);
|
if (tankClass) info.push(strings.common.tank_class_short[tankClass]);
|
||||||
if (type) info.push(strings.common.tree_type[type]);
|
if (type) info.push(strings.common.tree_type[type]);
|
||||||
|
|
||||||
return info.length === 0 ? strings.bot.common.filters.none : info.join(', ');
|
return info.length === 0 ? strings.bot.common.filters.none : info.join(", ");
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import { getTimeDaysAgo, Region } from '@blitzkit/core';
|
import { getTimeDaysAgo, type Region } from '@blitzkit/core';
|
||||||
import { PeriodSize } from '../discord/addPeriodSubCommands';
|
import type { PeriodSize } from '../discord/addPeriodSubCommands';
|
||||||
|
|
||||||
export function getPeriodStart(region: Region, period: PeriodSize) {
|
export function getPeriodStart(region: Region, period: PeriodSize) {
|
||||||
if (period === 'career') return 0;
|
if (period === 'career') return 0;
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import sharp from 'sharp';
|
import sharp from "sharp";
|
||||||
|
|
||||||
const cache: Record<string, Buffer> = {};
|
const cache: Record<string, Buffer> = {};
|
||||||
|
|
||||||
export async function iconPng(url: string) {
|
export async function iconPng(url: string) {
|
||||||
if (!url.endsWith('.webp')) return url;
|
if (!url.endsWith(".webp")) return url;
|
||||||
|
|
||||||
if (!cache[url]) {
|
if (!cache[url]) {
|
||||||
const imageResponse = await fetch(url);
|
const imageResponse = await fetch(url);
|
||||||
@@ -12,5 +12,5 @@ export async function iconPng(url: string) {
|
|||||||
cache[url] = imageBufferPNG;
|
cache[url] = imageBufferPNG;
|
||||||
}
|
}
|
||||||
|
|
||||||
return `data:image/png;base64,${cache[url].toString('base64')}`;
|
return `data:image/png;base64,${cache[url].toString("base64")}`;
|
||||||
}
|
}
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
import { TankClass, TankType } from '@blitzkit/core';
|
import { TankClass, TankType } from "@blitzkit/core";
|
||||||
import { SupplementaryStats } from '@blitzkit/core/src/blitz/getAccountInfo';
|
import type { SupplementaryStats } from "@blitzkit/core/src/blitz/getAccountInfo";
|
||||||
import { calculateWN8 } from '@blitzkit/core/src/statistics/calculateWN8';
|
import { calculateWN8 } from "@blitzkit/core/src/statistics/calculateWN8";
|
||||||
import { BlitzStats } from '@blitzkit/core/src/statistics/compositeStats';
|
import type { BlitzStats } from "@blitzkit/core/src/statistics/compositeStats";
|
||||||
import { sumAllStats } from '@blitzkit/core/src/statistics/sumAllStats';
|
import { sumAllStats } from "@blitzkit/core/src/statistics/sumAllStats";
|
||||||
import { tankDefinitions } from '../blitzkit/nonBlockingPromises';
|
import { tankDefinitions } from "../blitzkit/nonBlockingPromises";
|
||||||
import { blitzStarsTankAverages } from './tankAverages';
|
import { blitzStarsTankAverages } from "./tankAverages";
|
||||||
|
|
||||||
export interface StatFilters {
|
export interface StatFilters {
|
||||||
nation?: string;
|
nation?: string;
|
||||||
@@ -16,7 +16,7 @@ export interface StatFilters {
|
|||||||
|
|
||||||
export async function filterStats(
|
export async function filterStats(
|
||||||
{ diff, order }: DiffedTankStats,
|
{ diff, order }: DiffedTankStats,
|
||||||
filters: StatFilters,
|
filters: StatFilters
|
||||||
) {
|
) {
|
||||||
// tank, if provided, takes priority over all other filters
|
// tank, if provided, takes priority over all other filters
|
||||||
if (filters.tank) filters = { tank: filters.tank };
|
if (filters.tank) filters = { tank: filters.tank };
|
||||||
@@ -45,14 +45,14 @@ export async function filterStats(
|
|||||||
const battlesOfTanksWithAverages = filteredOrder.reduce<number>(
|
const battlesOfTanksWithAverages = filteredOrder.reduce<number>(
|
||||||
(accumulator, id) =>
|
(accumulator, id) =>
|
||||||
awaitedTankAverages[id] ? accumulator + diff[id].battles : accumulator,
|
awaitedTankAverages[id] ? accumulator + diff[id].battles : accumulator,
|
||||||
0,
|
0
|
||||||
);
|
);
|
||||||
const battlesOfTanksWithTankDefinition = filteredOrder.reduce<number>(
|
const battlesOfTanksWithTankDefinition = filteredOrder.reduce<number>(
|
||||||
(accumulator, id) =>
|
(accumulator, id) =>
|
||||||
awaitedTankDefinitions.tanks[id]
|
awaitedTankDefinitions.tanks[id]
|
||||||
? accumulator + diff[id].battles
|
? accumulator + diff[id].battles
|
||||||
: accumulator,
|
: accumulator,
|
||||||
0,
|
0
|
||||||
);
|
);
|
||||||
const supplementary = {
|
const supplementary = {
|
||||||
WN8:
|
WN8:
|
||||||
@@ -63,7 +63,7 @@ export async function filterStats(
|
|||||||
calculateWN8(awaitedTankAverages[id].all, diff[id]) *
|
calculateWN8(awaitedTankAverages[id].all, diff[id]) *
|
||||||
diff[id].battles
|
diff[id].battles
|
||||||
: accumulator,
|
: accumulator,
|
||||||
0,
|
0
|
||||||
) / battlesOfTanksWithAverages,
|
) / battlesOfTanksWithAverages,
|
||||||
tier:
|
tier:
|
||||||
filteredOrder.reduce<number>(
|
filteredOrder.reduce<number>(
|
||||||
@@ -72,7 +72,7 @@ export async function filterStats(
|
|||||||
? accumulator +
|
? accumulator +
|
||||||
awaitedTankDefinitions.tanks[id]!.tier * diff[id].battles
|
awaitedTankDefinitions.tanks[id]!.tier * diff[id].battles
|
||||||
: accumulator,
|
: accumulator,
|
||||||
0,
|
0
|
||||||
) / battlesOfTanksWithTankDefinition,
|
) / battlesOfTanksWithTankDefinition,
|
||||||
} satisfies SupplementaryStats;
|
} satisfies SupplementaryStats;
|
||||||
|
|
||||||
|
|||||||
@@ -1,17 +1,17 @@
|
|||||||
import { getAccountInfo, Region } from '@blitzkit/core';
|
import { getAccountInfo, type Region } from "@blitzkit/core";
|
||||||
import { buttonLink } from '../discord/buttonLink';
|
import { buttonLink } from "../discord/buttonLink";
|
||||||
|
|
||||||
export async function getBlitzStarsLinkButton(
|
export async function getBlitzStarsLinkButton(
|
||||||
region: Region,
|
region: Region,
|
||||||
id: number,
|
id: number,
|
||||||
tankId?: number,
|
tankId?: number
|
||||||
) {
|
) {
|
||||||
const { nickname } = await getAccountInfo(region, id);
|
const { nickname } = await getAccountInfo(region, id);
|
||||||
|
|
||||||
return buttonLink(
|
return buttonLink(
|
||||||
`https://www.blitzstars.com/player/${region}/${nickname}${
|
`https://www.blitzstars.com/player/${region}/${nickname}${
|
||||||
tankId ? `/tank/${tankId!}` : ''
|
tankId ? `/tank/${tankId!}` : ""
|
||||||
}`,
|
}`,
|
||||||
'BlitzStars',
|
"BlitzStars"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
import { Region, emptyAllStats, getAccountInfo } from '@blitzkit/core';
|
import { type Region, emptyAllStats, getAccountInfo } from '@blitzkit/core';
|
||||||
import {
|
import {
|
||||||
GetHistoriesOptions,
|
type GetHistoriesOptions,
|
||||||
Histories,
|
type Histories,
|
||||||
History,
|
type History,
|
||||||
getHistoriesDefaultOptions,
|
getHistoriesDefaultOptions,
|
||||||
} from '../../types/histories';
|
} from '../../types/histories';
|
||||||
import { PlayerStats } from './getPlayerStats';
|
import type { PlayerStats } from './getPlayerStats';
|
||||||
|
|
||||||
export async function getPlayerHistories(
|
export async function getPlayerHistories(
|
||||||
server: Region,
|
server: Region,
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { BlitzStats, Region } from '@blitzkit/core';
|
import type { BlitzStats, Region } from "@blitzkit/core";
|
||||||
|
|
||||||
interface IndividualPlayerStats {
|
interface IndividualPlayerStats {
|
||||||
clan: { clan_id: number; name: string; tag: string };
|
clan: { clan_id: number; name: string; tag: string };
|
||||||
@@ -25,13 +25,13 @@ export async function getPlayerStats<
|
|||||||
ReturnType = Ids extends number ? PlayerStats : PlayerStats[],
|
ReturnType = Ids extends number ? PlayerStats : PlayerStats[],
|
||||||
>(region: Region, ids: Ids) {
|
>(region: Region, ids: Ids) {
|
||||||
const stats = await Promise.all(
|
const stats = await Promise.all(
|
||||||
((typeof ids === 'number' ? [ids] : ids) as number[]).map((id) =>
|
((typeof ids === "number" ? [ids] : ids) as number[]).map((id) =>
|
||||||
fetch(`https://www.blitzstars.com/api/playerstats/${id}`).then(
|
fetch(`https://www.blitzstars.com/api/playerstats/${id}`).then(
|
||||||
(response) => response.json() as Promise<PlayerStats>,
|
(response) => response.json() as Promise<PlayerStats>
|
||||||
),
|
)
|
||||||
),
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
if (typeof ids === 'number') return stats[0] as ReturnType;
|
if (typeof ids === "number") return stats[0] as ReturnType;
|
||||||
return stats as ReturnType;
|
return stats as ReturnType;
|
||||||
}
|
}
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
import { BlitzStats, emptyAllStats, Region } from '@blitzkit/core';
|
import { type BlitzStats, emptyAllStats, type Region } from "@blitzkit/core";
|
||||||
import { Locale } from 'discord.js';
|
import { Locale } from "discord.js";
|
||||||
import { DiffedTankStats } from './filterStats';
|
import type { DiffedTankStats } from "./filterStats";
|
||||||
import {
|
import {
|
||||||
getTankHistories,
|
getTankHistories,
|
||||||
TankHistories,
|
type TankHistories,
|
||||||
TankHistoryRaw,
|
type TankHistoryRaw,
|
||||||
} from './getTankHistories';
|
} from "./getTankHistories";
|
||||||
|
|
||||||
const emptyTankHistoryNode: TankHistoryRaw = {
|
const emptyTankHistoryNode: TankHistoryRaw = {
|
||||||
account_id: 0,
|
account_id: 0,
|
||||||
@@ -22,7 +22,7 @@ export async function getStatsInPeriod(
|
|||||||
id: number,
|
id: number,
|
||||||
start: number,
|
start: number,
|
||||||
end: number,
|
end: number,
|
||||||
locale: Locale,
|
locale: Locale
|
||||||
) {
|
) {
|
||||||
const history = await getTankHistories(server, id, locale, {
|
const history = await getTankHistories(server, id, locale, {
|
||||||
includeLatestHistories: true,
|
includeLatestHistories: true,
|
||||||
@@ -43,8 +43,8 @@ export async function getStatsInPeriod(
|
|||||||
// find the ones played within the range
|
// find the ones played within the range
|
||||||
const inRangeTanks = tanks.filter((tankId) =>
|
const inRangeTanks = tanks.filter((tankId) =>
|
||||||
tankSortedHistory[tankId].some(
|
tankSortedHistory[tankId].some(
|
||||||
(node) => node.last_battle_time > start && node.last_battle_time < end,
|
(node) => node.last_battle_time > start && node.last_battle_time < end
|
||||||
),
|
)
|
||||||
);
|
);
|
||||||
const playedTanks: number[] = [];
|
const playedTanks: number[] = [];
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
import { Region, emptyAllStats, getTankStats } from '@blitzkit/core';
|
import { type Region, emptyAllStats, getTankStats } from "@blitzkit/core";
|
||||||
import { Locale } from 'discord.js';
|
import { Locale } from "discord.js";
|
||||||
import {
|
import {
|
||||||
GetHistoriesOptions,
|
type GetHistoriesOptions,
|
||||||
Histories,
|
type Histories,
|
||||||
History,
|
type History,
|
||||||
getHistoriesDefaultOptions,
|
getHistoriesDefaultOptions,
|
||||||
} from '../../types/histories';
|
} from "../../types/histories";
|
||||||
import { UserError } from '../blitzkit/userError';
|
import { UserError } from "../blitzkit/userError";
|
||||||
import { translator } from '../localization/translator';
|
import { translator } from "../localization/translator";
|
||||||
|
|
||||||
export interface TankHistory extends History {
|
export interface TankHistory extends History {
|
||||||
tank_id: number;
|
tank_id: number;
|
||||||
@@ -36,12 +36,12 @@ export async function getTankHistories(
|
|||||||
server: Region,
|
server: Region,
|
||||||
id: number,
|
id: number,
|
||||||
locale: Locale,
|
locale: Locale,
|
||||||
options?: Partial<GetTankHistoriesOptions>,
|
options?: Partial<GetTankHistoriesOptions>
|
||||||
) {
|
) {
|
||||||
const { strings } = translator(locale);
|
const { strings } = translator(locale);
|
||||||
const mergedOptions = { ...getTankHistoriesDefaultOptions, ...options };
|
const mergedOptions = { ...getTankHistoriesDefaultOptions, ...options };
|
||||||
const tankHistoriesResponse = await fetch(
|
const tankHistoriesResponse = await fetch(
|
||||||
`https://www.blitzstars.com/api/tankhistories/for/${id}/`,
|
`https://www.blitzstars.com/api/tankhistories/for/${id}/`
|
||||||
);
|
);
|
||||||
const tankHistories = (
|
const tankHistories = (
|
||||||
(await tankHistoriesResponse.json()) as TankHistoriesRaw
|
(await tankHistoriesResponse.json()) as TankHistoriesRaw
|
||||||
@@ -51,7 +51,7 @@ export async function getTankHistories(
|
|||||||
all: history.all,
|
all: history.all,
|
||||||
last_battle_time: history.last_battle_time,
|
last_battle_time: history.last_battle_time,
|
||||||
tank_id: history.tank_id,
|
tank_id: history.tank_id,
|
||||||
}) satisfies TankHistory,
|
}) satisfies TankHistory
|
||||||
);
|
);
|
||||||
const compliantTanks: number[] = [];
|
const compliantTanks: number[] = [];
|
||||||
const lastBattles: Record<number, number> = {};
|
const lastBattles: Record<number, number> = {};
|
||||||
@@ -73,7 +73,7 @@ export async function getTankHistories(
|
|||||||
lastBattles[tank_id] = battles;
|
lastBattles[tank_id] = battles;
|
||||||
|
|
||||||
return complies;
|
return complies;
|
||||||
},
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
const latestNodes: TankHistories = [];
|
const latestNodes: TankHistories = [];
|
||||||
@@ -112,7 +112,7 @@ export async function getTankHistories(
|
|||||||
all: emptyAllStats,
|
all: emptyAllStats,
|
||||||
last_battle_time: -Infinity,
|
last_battle_time: -Infinity,
|
||||||
tank_id: tankId,
|
tank_id: tankId,
|
||||||
} satisfies TankHistory),
|
} satisfies TankHistory)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import {
|
|||||||
TANK_TYPES,
|
TANK_TYPES,
|
||||||
} from '@blitzkit/core';
|
} from '@blitzkit/core';
|
||||||
import {
|
import {
|
||||||
APIApplicationCommandOptionChoice,
|
type APIApplicationCommandOptionChoice,
|
||||||
Locale,
|
Locale,
|
||||||
SlashCommandBuilder,
|
SlashCommandBuilder,
|
||||||
SlashCommandSubcommandBuilder,
|
SlashCommandSubcommandBuilder,
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
import { REGIONS } from '@blitzkit/core';
|
import { REGIONS } from "@blitzkit/core";
|
||||||
import {
|
import {
|
||||||
APIApplicationCommandOptionChoice,
|
type APIApplicationCommandOptionChoice,
|
||||||
Locale,
|
Locale,
|
||||||
SlashCommandStringOption,
|
SlashCommandStringOption,
|
||||||
} from 'discord.js';
|
} from "discord.js";
|
||||||
import { translator } from '../localization/translator';
|
import { translator } from "../localization/translator";
|
||||||
import { localizationObject } from './localizationObject';
|
import { localizationObject } from "./localizationObject";
|
||||||
|
|
||||||
export function addRegionChoices(option: SlashCommandStringOption) {
|
export function addRegionChoices(option: SlashCommandStringOption) {
|
||||||
const { strings } = translator(Locale.EnglishUS);
|
const { strings } = translator(Locale.EnglishUS);
|
||||||
@@ -16,14 +16,14 @@ export function addRegionChoices(option: SlashCommandStringOption) {
|
|||||||
localizationObject(
|
localizationObject(
|
||||||
(strings) => strings.bot.common.options.region.name,
|
(strings) => strings.bot.common.options.region.name,
|
||||||
undefined,
|
undefined,
|
||||||
true,
|
true
|
||||||
),
|
)
|
||||||
)
|
)
|
||||||
.setDescription(strings.bot.common.options.region.description)
|
.setDescription(strings.bot.common.options.region.description)
|
||||||
.setDescriptionLocalizations(
|
.setDescriptionLocalizations(
|
||||||
localizationObject(
|
localizationObject(
|
||||||
(strings) => strings.bot.common.options.region.description,
|
(strings) => strings.bot.common.options.region.description
|
||||||
),
|
)
|
||||||
)
|
)
|
||||||
.addChoices(
|
.addChoices(
|
||||||
...REGIONS.map(
|
...REGIONS.map(
|
||||||
@@ -32,10 +32,10 @@ export function addRegionChoices(option: SlashCommandStringOption) {
|
|||||||
value: region,
|
value: region,
|
||||||
name: strings.common.regions.normal[region],
|
name: strings.common.regions.normal[region],
|
||||||
name_localizations: localizationObject(
|
name_localizations: localizationObject(
|
||||||
(strings) => strings.common.regions.normal[region],
|
(strings) => strings.common.regions.normal[region]
|
||||||
),
|
),
|
||||||
}) satisfies APIApplicationCommandOptionChoice,
|
}) satisfies APIApplicationCommandOptionChoice
|
||||||
),
|
)
|
||||||
)
|
)
|
||||||
.setRequired(true);
|
.setRequired(true);
|
||||||
}
|
}
|
||||||
@@ -1,13 +1,13 @@
|
|||||||
import { numberToRomanNumeral } from '@blitzkit/core';
|
import { numberToRomanNumeral } from "@blitzkit/core";
|
||||||
import { literals } from '@blitzkit/i18n';
|
import { literals } from "@blitzkit/i18n";
|
||||||
import {
|
import {
|
||||||
APIApplicationCommandOptionChoice,
|
APIApplicationCommandOptionChoice,
|
||||||
Locale,
|
Locale,
|
||||||
SlashCommandStringOption,
|
SlashCommandStringOption,
|
||||||
} from 'discord.js';
|
} from "discord.js";
|
||||||
import { range } from 'lodash-es';
|
import { range } from "lodash-es";
|
||||||
import { translator } from '../localization/translator';
|
import { translator } from "../localization/translator";
|
||||||
import { localizationObject } from './localizationObject';
|
import { localizationObject } from "./localizationObject";
|
||||||
|
|
||||||
export function addTierChoices(option: SlashCommandStringOption) {
|
export function addTierChoices(option: SlashCommandStringOption) {
|
||||||
const { strings } = translator(Locale.EnglishUS);
|
const { strings } = translator(Locale.EnglishUS);
|
||||||
@@ -18,30 +18,30 @@ export function addTierChoices(option: SlashCommandStringOption) {
|
|||||||
localizationObject(
|
localizationObject(
|
||||||
(strings) => strings.bot.common.options.tier.name,
|
(strings) => strings.bot.common.options.tier.name,
|
||||||
undefined,
|
undefined,
|
||||||
true,
|
true
|
||||||
),
|
)
|
||||||
)
|
)
|
||||||
.setDescription(strings.bot.common.options.tier.description)
|
.setDescription(strings.bot.common.options.tier.description)
|
||||||
.setDescriptionLocalizations(
|
.setDescriptionLocalizations(
|
||||||
localizationObject(
|
localizationObject(
|
||||||
(strings) => strings.bot.common.options.tier.description,
|
(strings) => strings.bot.common.options.tier.description
|
||||||
),
|
)
|
||||||
)
|
)
|
||||||
.setChoices(
|
.setChoices(
|
||||||
...range(10, 0).map(
|
...range(10, 0).map(
|
||||||
(tier) =>
|
(tier) =>
|
||||||
({
|
({
|
||||||
name: literals(strings.bot.common.options.tier.choices.tier, [
|
name: literals(strings.bot.common.options.tier.choices.tier, {
|
||||||
`${tier}`,
|
tier_1: tier,
|
||||||
numberToRomanNumeral(tier),
|
tier_2: numberToRomanNumeral(tier),
|
||||||
]),
|
}),
|
||||||
value: `${tier}`,
|
value: `${tier}`,
|
||||||
name_localizations: localizationObject(
|
name_localizations: localizationObject(
|
||||||
(strings) => strings.bot.common.options.tier.choices.tier,
|
(strings) => strings.bot.common.options.tier.choices.tier,
|
||||||
[`${tier}`, numberToRomanNumeral(tier)],
|
{ tier_1: tier, tier_2: numberToRomanNumeral(tier) }
|
||||||
),
|
),
|
||||||
}) satisfies APIApplicationCommandOptionChoice,
|
}) satisfies APIApplicationCommandOptionChoice
|
||||||
),
|
)
|
||||||
)
|
)
|
||||||
.setRequired(true);
|
.setRequired(true);
|
||||||
}
|
}
|
||||||
@@ -1,25 +1,25 @@
|
|||||||
import { fetchTankNames, SEARCH_KEYS, TankType } from '@blitzkit/core';
|
import { fetchTankNames, SEARCH_KEYS, TankType } from "@blitzkit/core";
|
||||||
import {
|
import {
|
||||||
ApplicationCommandOptionChoiceData,
|
type ApplicationCommandOptionChoiceData,
|
||||||
AutocompleteInteraction,
|
AutocompleteInteraction,
|
||||||
CacheType,
|
type CacheType,
|
||||||
} from 'discord.js';
|
} from "discord.js";
|
||||||
import { go } from 'fuzzysort';
|
import { go } from "fuzzysort";
|
||||||
import { tankNames } from '../blitzkit/nonBlockingPromises';
|
import { tankNames } from "../blitzkit/nonBlockingPromises";
|
||||||
import { translator } from '../localization/translator';
|
import { translator } from "../localization/translator";
|
||||||
import {
|
import {
|
||||||
DISCORD_CHOICES_MAX_NAME_SIZE,
|
DISCORD_CHOICES_MAX_NAME_SIZE,
|
||||||
OVERFLOW_SUFFIX,
|
OVERFLOW_SUFFIX,
|
||||||
} from './autocompleteClan/constants';
|
} from "./autocompleteClan/constants";
|
||||||
|
|
||||||
export const tankNamesTechTreeOnly = fetchTankNames().then((names) =>
|
export const tankNamesTechTreeOnly = fetchTankNames().then((names) =>
|
||||||
names.filter((tank) => tank.treeType === TankType.RESEARCHABLE),
|
names.filter((tank) => tank.treeType === TankType.RESEARCHABLE)
|
||||||
);
|
);
|
||||||
|
|
||||||
export async function autocompleteTanks(
|
export async function autocompleteTanks(
|
||||||
interaction: AutocompleteInteraction<CacheType>,
|
interaction: AutocompleteInteraction<CacheType>,
|
||||||
techTreeOnly = false,
|
techTreeOnly = false,
|
||||||
fields = ['tank'],
|
fields = ["tank"]
|
||||||
) {
|
) {
|
||||||
const { unwrap } = translator(interaction.locale);
|
const { unwrap } = translator(interaction.locale);
|
||||||
const focusedOption = interaction.options.getFocused(true);
|
const focusedOption = interaction.options.getFocused(true);
|
||||||
@@ -31,7 +31,7 @@ export async function autocompleteTanks(
|
|||||||
go(
|
go(
|
||||||
focusedOption.value,
|
focusedOption.value,
|
||||||
await (techTreeOnly ? tankNamesTechTreeOnly : tankNames),
|
await (techTreeOnly ? tankNamesTechTreeOnly : tankNames),
|
||||||
{ keys: SEARCH_KEYS, limit: 10 },
|
{ keys: SEARCH_KEYS, limit: 10 }
|
||||||
).map(async (item) => {
|
).map(async (item) => {
|
||||||
let name = unwrap(item.obj.searchableName);
|
let name = unwrap(item.obj.searchableName);
|
||||||
|
|
||||||
@@ -42,7 +42,7 @@ export async function autocompleteTanks(
|
|||||||
0,
|
0,
|
||||||
unwrap(item.obj.searchableName).length -
|
unwrap(item.obj.searchableName).length -
|
||||||
overSize -
|
overSize -
|
||||||
OVERFLOW_SUFFIX.length,
|
OVERFLOW_SUFFIX.length
|
||||||
)}${OVERFLOW_SUFFIX}`;
|
)}${OVERFLOW_SUFFIX}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -50,8 +50,8 @@ export async function autocompleteTanks(
|
|||||||
name,
|
name,
|
||||||
value: `${item.obj.id}`,
|
value: `${item.obj.id}`,
|
||||||
} satisfies ApplicationCommandOptionChoiceData<string>;
|
} satisfies ApplicationCommandOptionChoiceData<string>;
|
||||||
}),
|
})
|
||||||
)
|
)
|
||||||
: [],
|
: []
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -1,13 +1,13 @@
|
|||||||
import {
|
import {
|
||||||
ButtonBuilder,
|
ButtonBuilder,
|
||||||
ButtonStyle,
|
ButtonStyle,
|
||||||
ComponentEmojiResolvable,
|
type ComponentEmojiResolvable,
|
||||||
} from 'discord.js';
|
} from "discord.js";
|
||||||
|
|
||||||
export function buttonLink(
|
export function buttonLink(
|
||||||
url: string,
|
url: string,
|
||||||
label: string,
|
label: string,
|
||||||
emoji?: ComponentEmojiResolvable,
|
emoji?: ComponentEmojiResolvable
|
||||||
) {
|
) {
|
||||||
const button = new ButtonBuilder()
|
const button = new ButtonBuilder()
|
||||||
.setStyle(ButtonStyle.Link)
|
.setStyle(ButtonStyle.Link)
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
import {
|
import {
|
||||||
ButtonBuilder,
|
ButtonBuilder,
|
||||||
ButtonStyle,
|
ButtonStyle,
|
||||||
ComponentEmojiResolvable,
|
type ComponentEmojiResolvable,
|
||||||
} from 'discord.js';
|
} from "discord.js";
|
||||||
|
|
||||||
export function buttonPrimary(
|
export function buttonPrimary(
|
||||||
id: string,
|
id: string,
|
||||||
label: string,
|
label: string,
|
||||||
emoji?: ComponentEmojiResolvable,
|
emoji?: ComponentEmojiResolvable
|
||||||
) {
|
) {
|
||||||
const button = new ButtonBuilder()
|
const button = new ButtonBuilder()
|
||||||
.setCustomId(id)
|
.setCustomId(id)
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { CacheType, ChatInputCommandInteraction } from 'discord.js';
|
import { type CacheType, ChatInputCommandInteraction } from "discord.js";
|
||||||
|
|
||||||
export interface Parameters {
|
export interface Parameters {
|
||||||
[key: string]: string | number | boolean | undefined | null;
|
[key: string]: string | number | boolean | undefined | null;
|
||||||
@@ -9,7 +9,7 @@ export interface Parameters {
|
|||||||
|
|
||||||
export function commandToURL(
|
export function commandToURL(
|
||||||
interaction: ChatInputCommandInteraction<CacheType>,
|
interaction: ChatInputCommandInteraction<CacheType>,
|
||||||
parameters?: Parameters,
|
parameters?: Parameters
|
||||||
) {
|
) {
|
||||||
const pathname = [
|
const pathname = [
|
||||||
interaction.commandName,
|
interaction.commandName,
|
||||||
@@ -17,11 +17,11 @@ export function commandToURL(
|
|||||||
interaction.options.getSubcommand(false),
|
interaction.options.getSubcommand(false),
|
||||||
]
|
]
|
||||||
.filter(Boolean)
|
.filter(Boolean)
|
||||||
.join('/');
|
.join("/");
|
||||||
const params = (parameters ? Object.entries(parameters) : [])
|
const params = (parameters ? Object.entries(parameters) : [])
|
||||||
.filter(([, value]) => value !== undefined && value !== null)
|
.filter(([, value]) => value !== undefined && value !== null)
|
||||||
.map(([key, value]) => `${key}=${value}`)
|
.map(([key, value]) => `${key}=${value}`)
|
||||||
.join('&');
|
.join("&");
|
||||||
|
|
||||||
return `${pathname}${params.length > 0 ? `?${params}` : ''}`;
|
return `${pathname}${params.length > 0 ? `?${params}` : ""}`;
|
||||||
}
|
}
|
||||||
@@ -1,12 +1,12 @@
|
|||||||
import { BlitzKitStrings } from '@blitzkit/i18n';
|
import { type BlitzKitStrings } from "@blitzkit/i18n";
|
||||||
import {
|
import {
|
||||||
Locale,
|
Locale,
|
||||||
SlashCommandBuilder,
|
SlashCommandBuilder,
|
||||||
SlashCommandSubcommandBuilder,
|
SlashCommandSubcommandBuilder,
|
||||||
SlashCommandSubcommandGroupBuilder,
|
SlashCommandSubcommandGroupBuilder,
|
||||||
} from 'discord.js';
|
} from "discord.js";
|
||||||
import { translator } from '../localization/translator';
|
import { translator } from "../localization/translator";
|
||||||
import { localizationObject } from './localizationObject';
|
import { localizationObject } from "./localizationObject";
|
||||||
|
|
||||||
interface CreateLocalizedCommandSubcommand {
|
interface CreateLocalizedCommandSubcommand {
|
||||||
subcommand: string;
|
subcommand: string;
|
||||||
@@ -22,12 +22,12 @@ export function createLocalizedCommand(
|
|||||||
command: string,
|
command: string,
|
||||||
sub?:
|
sub?:
|
||||||
| CreateLocalizedCommandSubcommand[]
|
| CreateLocalizedCommandSubcommand[]
|
||||||
| CreateLocalizedCommandSubcommandGroup[],
|
| CreateLocalizedCommandSubcommandGroup[]
|
||||||
) {
|
) {
|
||||||
const commandPathItem = command.replaceAll(
|
const commandPathItem = command.replaceAll(
|
||||||
'-',
|
"-",
|
||||||
'_',
|
"_"
|
||||||
) as keyof BlitzKitStrings['bot']['commands'];
|
) as keyof BlitzKitStrings["bot"]["commands"];
|
||||||
const { strings } = translator(Locale.EnglishUS);
|
const { strings } = translator(Locale.EnglishUS);
|
||||||
const slashCommand = new SlashCommandBuilder()
|
const slashCommand = new SlashCommandBuilder()
|
||||||
.setName(command)
|
.setName(command)
|
||||||
@@ -35,19 +35,19 @@ export function createLocalizedCommand(
|
|||||||
localizationObject(
|
localizationObject(
|
||||||
(strings) => strings.bot.commands[commandPathItem].name,
|
(strings) => strings.bot.commands[commandPathItem].name,
|
||||||
undefined,
|
undefined,
|
||||||
true,
|
true
|
||||||
),
|
)
|
||||||
)
|
)
|
||||||
.setDescription(strings.bot.commands[commandPathItem].description)
|
.setDescription(strings.bot.commands[commandPathItem].description)
|
||||||
.setDescriptionLocalizations(
|
.setDescriptionLocalizations(
|
||||||
localizationObject(
|
localizationObject(
|
||||||
(strings) => strings.bot.commands[commandPathItem].description,
|
(strings) => strings.bot.commands[commandPathItem].description
|
||||||
),
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
if (sub) {
|
if (sub) {
|
||||||
sub.map((subItem) => {
|
sub.map((subItem) => {
|
||||||
if ('subcommand' in subItem) {
|
if ("subcommand" in subItem) {
|
||||||
const subcommandNameLocalizations = localizationObject(
|
const subcommandNameLocalizations = localizationObject(
|
||||||
(strings) =>
|
(strings) =>
|
||||||
(
|
(
|
||||||
@@ -56,7 +56,7 @@ export function createLocalizedCommand(
|
|||||||
}
|
}
|
||||||
).subcommands[subItem.subcommand].name,
|
).subcommands[subItem.subcommand].name,
|
||||||
undefined,
|
undefined,
|
||||||
true,
|
true
|
||||||
);
|
);
|
||||||
const subcommandDescriptionLocalizations = localizationObject(
|
const subcommandDescriptionLocalizations = localizationObject(
|
||||||
(strings) =>
|
(strings) =>
|
||||||
@@ -64,7 +64,7 @@ export function createLocalizedCommand(
|
|||||||
strings.bot.commands[commandPathItem] as unknown as {
|
strings.bot.commands[commandPathItem] as unknown as {
|
||||||
subcommands: Record<string, { description: string }>;
|
subcommands: Record<string, { description: string }>;
|
||||||
}
|
}
|
||||||
).subcommands[subItem.subcommand].description,
|
).subcommands[subItem.subcommand].description
|
||||||
);
|
);
|
||||||
|
|
||||||
slashCommand.addSubcommand((option) => {
|
slashCommand.addSubcommand((option) => {
|
||||||
@@ -78,7 +78,7 @@ export function createLocalizedCommand(
|
|||||||
strings.bot.commands[commandPathItem] as unknown as {
|
strings.bot.commands[commandPathItem] as unknown as {
|
||||||
subcommands: Record<string, { description: string }>;
|
subcommands: Record<string, { description: string }>;
|
||||||
}
|
}
|
||||||
).subcommands[subItem.subcommand].description,
|
).subcommands[subItem.subcommand].description
|
||||||
)
|
)
|
||||||
.setDescriptionLocalizations(subcommandDescriptionLocalizations);
|
.setDescriptionLocalizations(subcommandDescriptionLocalizations);
|
||||||
});
|
});
|
||||||
@@ -91,7 +91,7 @@ export function createLocalizedCommand(
|
|||||||
}
|
}
|
||||||
).groups[subItem.group].name,
|
).groups[subItem.group].name,
|
||||||
undefined,
|
undefined,
|
||||||
true,
|
true
|
||||||
);
|
);
|
||||||
const subcommandDescriptionLocalizations = localizationObject(
|
const subcommandDescriptionLocalizations = localizationObject(
|
||||||
(strings) =>
|
(strings) =>
|
||||||
@@ -99,7 +99,7 @@ export function createLocalizedCommand(
|
|||||||
strings.bot.commands[commandPathItem] as unknown as {
|
strings.bot.commands[commandPathItem] as unknown as {
|
||||||
groups: Record<string, { description: string }>;
|
groups: Record<string, { description: string }>;
|
||||||
}
|
}
|
||||||
).groups[subItem.group].description,
|
).groups[subItem.group].description
|
||||||
);
|
);
|
||||||
|
|
||||||
slashCommand.addSubcommandGroup((option) => {
|
slashCommand.addSubcommandGroup((option) => {
|
||||||
@@ -113,7 +113,7 @@ export function createLocalizedCommand(
|
|||||||
strings.bot.commands[commandPathItem] as unknown as {
|
strings.bot.commands[commandPathItem] as unknown as {
|
||||||
groups: Record<string, { description: string }>;
|
groups: Record<string, { description: string }>;
|
||||||
}
|
}
|
||||||
).groups[subItem.group].description,
|
).groups[subItem.group].description
|
||||||
)
|
)
|
||||||
.setDescriptionLocalizations(subcommandDescriptionLocalizations);
|
.setDescriptionLocalizations(subcommandDescriptionLocalizations);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,17 +1,17 @@
|
|||||||
import { ChatInputCommandInteraction } from 'discord.js';
|
import { ChatInputCommandInteraction } from "discord.js";
|
||||||
import { PeriodType } from './addPeriodSubCommands';
|
import type { PeriodType } from "./addPeriodSubCommands";
|
||||||
|
|
||||||
export function getCustomPeriodParams(
|
export function getCustomPeriodParams(
|
||||||
interaction: ChatInputCommandInteraction,
|
interaction: ChatInputCommandInteraction,
|
||||||
forcedNonCustomPeriod = false,
|
forcedNonCustomPeriod = false
|
||||||
) {
|
) {
|
||||||
if (
|
if (
|
||||||
!forcedNonCustomPeriod &&
|
!forcedNonCustomPeriod &&
|
||||||
(interaction.options.getSubcommand() as PeriodType) === 'custom'
|
(interaction.options.getSubcommand() as PeriodType) === "custom"
|
||||||
) {
|
) {
|
||||||
return {
|
return {
|
||||||
start: interaction.options.getInteger('start', true),
|
start: interaction.options.getInteger("start", true),
|
||||||
end: interaction.options.getInteger('end', true),
|
end: interaction.options.getInteger("end", true),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,19 +1,19 @@
|
|||||||
import { TankClass, TankType } from '@blitzkit/core';
|
import { TankClass, TankType } from "@blitzkit/core";
|
||||||
import { ButtonInteraction } from 'discord.js';
|
import { ButtonInteraction } from "discord.js";
|
||||||
import { StatFilters } from '../blitzstars/filterStats';
|
import type { StatFilters } from "../blitzstars/filterStats";
|
||||||
|
|
||||||
export function getFiltersFromButton(interaction: ButtonInteraction) {
|
export function getFiltersFromButton(interaction: ButtonInteraction) {
|
||||||
const url = new URL(`https://example.com/${interaction.customId}`);
|
const url = new URL(`https://example.com/${interaction.customId}`);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
nation: url.searchParams.get('nation') ?? undefined,
|
nation: url.searchParams.get("nation") ?? undefined,
|
||||||
tank: parseInt(url.searchParams.get('tank') ?? '0') || undefined,
|
tank: parseInt(url.searchParams.get("tank") ?? "0") || undefined,
|
||||||
class:
|
class:
|
||||||
(Number(url.searchParams.get('class')) as TankClass | undefined) ??
|
(Number(url.searchParams.get("class")) as TankClass | undefined) ??
|
||||||
undefined,
|
undefined,
|
||||||
type:
|
type:
|
||||||
(Number(url.searchParams.get('type')) as TankType | undefined) ??
|
(Number(url.searchParams.get("type")) as TankType | undefined) ??
|
||||||
undefined,
|
undefined,
|
||||||
tier: parseInt(url.searchParams.get('tier') ?? '0') || undefined,
|
tier: parseInt(url.searchParams.get("tier") ?? "0") || undefined,
|
||||||
} satisfies StatFilters;
|
} satisfies StatFilters;
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import { ChatInputCommandInteraction } from 'discord.js';
|
import { ChatInputCommandInteraction } from 'discord.js';
|
||||||
import { resolveTankId } from '../blitz/resolveTankId';
|
import { resolveTankId } from '../blitz/resolveTankId';
|
||||||
import { StatFilters } from '../blitzstars/filterStats';
|
import type { StatFilters } from '../blitzstars/filterStats';
|
||||||
|
|
||||||
export async function getFiltersFromCommand(
|
export async function getFiltersFromCommand(
|
||||||
interaction: ChatInputCommandInteraction,
|
interaction: ChatInputCommandInteraction,
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
import { literals } from '@blitzkit/i18n';
|
import { literals } from "@blitzkit/i18n";
|
||||||
import { Locale } from 'discord.js';
|
import { Locale } from "discord.js";
|
||||||
import { translator } from '../localization/translator';
|
import { translator } from "../localization/translator";
|
||||||
import { PeriodSize } from './addPeriodSubCommands';
|
import type { PeriodSize } from "./addPeriodSubCommands";
|
||||||
|
|
||||||
export function getPeriodOptionName(period: PeriodSize, locale: Locale) {
|
export function getPeriodOptionName(period: PeriodSize, locale: Locale) {
|
||||||
const { strings } = translator(locale);
|
const { strings } = translator(locale);
|
||||||
if (period === 'career') return strings.bot.common.periods.career;
|
if (period === "career") return strings.bot.common.periods.career;
|
||||||
if (period === 'today') return strings.bot.common.periods.today;
|
if (period === "today") return strings.bot.common.periods.today;
|
||||||
return literals(strings.bot.common.periods.days, [period]);
|
return literals(strings.bot.common.periods.days, { days: period });
|
||||||
}
|
}
|
||||||
@@ -1,15 +1,15 @@
|
|||||||
import { BlitzKitStrings, literals as literalsFunc } from '@blitzkit/i18n';
|
import { type BlitzKitStrings, literals as literalsFunc } from "@blitzkit/i18n";
|
||||||
import { Locale } from 'discord.js';
|
import { Locale } from "discord.js";
|
||||||
import { SUPPORTED_LOCALES_DISCORD } from '../localization/strings/constants';
|
import { SUPPORTED_LOCALES_DISCORD } from "../localization/strings/constants";
|
||||||
import { translator } from '../localization/translator';
|
import { translator } from "../localization/translator";
|
||||||
|
|
||||||
const validNameRegex =
|
const validNameRegex =
|
||||||
/^[\p{Ll}\p{Lm}\p{Lo}\p{N}\p{sc=Devanagari}\p{sc=Thai}_-]+$/u;
|
/^[\p{Ll}\p{Lm}\p{Lo}\p{N}\p{sc=Devanagari}\p{sc=Thai}_-]+$/u;
|
||||||
|
|
||||||
export function localizationObject(
|
export function localizationObject(
|
||||||
path: (strings: BlitzKitStrings) => string,
|
path: (strings: BlitzKitStrings) => string,
|
||||||
literals: string[] = [],
|
literals?: Record<string, string | number>,
|
||||||
strict = false,
|
strict = false
|
||||||
) {
|
) {
|
||||||
return SUPPORTED_LOCALES_DISCORD.reduce<Partial<Record<Locale, string>>>(
|
return SUPPORTED_LOCALES_DISCORD.reduce<Partial<Record<Locale, string>>>(
|
||||||
(localizations, locale) => {
|
(localizations, locale) => {
|
||||||
@@ -20,7 +20,7 @@ export function localizationObject(
|
|||||||
|
|
||||||
if (!isValid) {
|
if (!isValid) {
|
||||||
console.warn(
|
console.warn(
|
||||||
`Invalid localization for ${locale} (${path}): ${translation}; skipping...`,
|
`Invalid localization for ${locale} (${path}): ${translation}; skipping...`
|
||||||
);
|
);
|
||||||
return localizations;
|
return localizations;
|
||||||
}
|
}
|
||||||
@@ -30,6 +30,6 @@ export function localizationObject(
|
|||||||
[locale]: translation,
|
[locale]: translation,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
{},
|
{}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
Loaded 100 of 372 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user