mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-21 10:47:04 +02:00
feat: functionality and icons
This commit is contained in:
1 parent
035f751bf1
commit
787d3ae6ea
8 files changed
+253
-40
No files matched your search
@@ -0,0 +1,39 @@
|
|||||||
|
import sharp from 'sharp';
|
||||||
|
import { readDVPLFile } from '../../src/core/blitz/readDVPLFile';
|
||||||
|
import { commitAssets } from '../../src/core/blitzkrieg/commitAssets';
|
||||||
|
import { FileChange } from '../../src/core/blitzkrieg/commitMultipleFiles';
|
||||||
|
import { DATA } from './constants';
|
||||||
|
|
||||||
|
const ICONS = [
|
||||||
|
['currency_silver_m.packed.webp', 'silver'],
|
||||||
|
['currency_premium_xl.packed.webp', 'premium'],
|
||||||
|
['currency_gold_m.packed.webp', 'gold'],
|
||||||
|
['currency_free-xp_xl.packed.webp', 'free-xp'],
|
||||||
|
['currency_elite-xp_xl.packed.webp', 'elite-xp'],
|
||||||
|
['currency_crew-xp_xl.packed.webp', 'crew-xp'],
|
||||||
|
['currency_battle-xp_xl.packed.webp', 'xp'],
|
||||||
|
];
|
||||||
|
|
||||||
|
export async function currencies(production: boolean) {
|
||||||
|
console.log('Building currency icons...');
|
||||||
|
|
||||||
|
const changes = await Promise.all(
|
||||||
|
ICONS.map(async ([file, name]) => {
|
||||||
|
const content = (
|
||||||
|
await sharp(
|
||||||
|
await readDVPLFile(`${DATA}/Gfx/Lobby/currency/${file}.dvpl`),
|
||||||
|
)
|
||||||
|
.trim()
|
||||||
|
.toBuffer()
|
||||||
|
).toString('base64');
|
||||||
|
|
||||||
|
return {
|
||||||
|
content,
|
||||||
|
encoding: 'base64',
|
||||||
|
path: `icons/currencies/${name}.webp`,
|
||||||
|
} satisfies FileChange;
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
await commitAssets('currency icons', changes, production);
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import { readdir } from 'fs/promises';
|
import { readdir, writeFile } from 'fs/promises';
|
||||||
import { parse as parsePath } from 'path';
|
import { parse as parsePath } from 'path';
|
||||||
import { Vector3Tuple } from 'three';
|
import { Vector3Tuple } from 'three';
|
||||||
import { parse as parseYaml } from 'yaml';
|
import { parse as parseYaml } from 'yaml';
|
||||||
@@ -369,10 +369,6 @@ export async function definitions(production: boolean) {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const tankXps = new Map<number, number>();
|
const tankXps = new Map<number, number>();
|
||||||
const gunXps = new Map<number, number>();
|
|
||||||
const turretXps = new Map<number, number>();
|
|
||||||
const engineXps = new Map<number, number>();
|
|
||||||
const trackXps = new Map<number, number>();
|
|
||||||
|
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
nations.map(async (nation) => {
|
nations.map(async (nation) => {
|
||||||
@@ -406,6 +402,10 @@ export async function definitions(production: boolean) {
|
|||||||
);
|
);
|
||||||
|
|
||||||
for (const tankKey in tankList.root) {
|
for (const tankKey in tankList.root) {
|
||||||
|
const gunXps = new Map<number, number>();
|
||||||
|
const turretXps = new Map<number, number>();
|
||||||
|
const engineXps = new Map<number, number>();
|
||||||
|
const trackXps = new Map<number, number>();
|
||||||
const tank = tankList.root[tankKey];
|
const tank = tankList.root[tankKey];
|
||||||
const tankPrice: TankDefinitionPrice =
|
const tankPrice: TankDefinitionPrice =
|
||||||
typeof tank.price === 'number'
|
typeof tank.price === 'number'
|
||||||
@@ -891,28 +891,28 @@ export async function definitions(production: boolean) {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Object.values(tankDefinitions[tankId].turrets).forEach((turret) => {
|
||||||
|
turret.xp = turretXps.get(turret.id);
|
||||||
|
|
||||||
|
Object.values(turret.guns).forEach((gun) => {
|
||||||
|
gun.xp = gunXps.get(gun.id);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
Object.values(tankDefinitions[tankId].engines).forEach((engine) => {
|
||||||
|
engine.xp = engineXps.get(engine.id);
|
||||||
|
});
|
||||||
|
|
||||||
|
Object.values(tankDefinitions[tankId].tracks).forEach((track) => {
|
||||||
|
track.xp = trackXps.get(track.id);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
Object.values(tankDefinitions).forEach((tank) => {
|
Object.values(tankDefinitions).forEach((tank) => {
|
||||||
tank.xp = tankXps.get(tank.id);
|
tank.xp = tankXps.get(tank.id);
|
||||||
|
|
||||||
Object.values(tank.turrets).forEach((turret) => {
|
|
||||||
turret.xp = turretXps.get(turret.id);
|
|
||||||
|
|
||||||
Object.values(turret.guns).forEach((gun) => {
|
|
||||||
gun.xp = gunXps.get(gun.id);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
Object.values(tank.engines).forEach((engine) => {
|
|
||||||
engine.xp = engineXps.get(engine.id);
|
|
||||||
});
|
|
||||||
|
|
||||||
Object.values(tank.tracks).forEach((track) => {
|
|
||||||
track.xp = trackXps.get(track.id);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
Object.values(tankDefinitions).forEach((tank) => {
|
Object.values(tankDefinitions).forEach((tank) => {
|
||||||
@@ -1084,6 +1084,10 @@ export async function definitions(production: boolean) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
writeFile(
|
||||||
|
'test.tanks.cdon.lz4',
|
||||||
|
Buffer.from(superCompress(tankDefinitions), 'base64'),
|
||||||
|
);
|
||||||
await commitAssets(
|
await commitAssets(
|
||||||
'definitions',
|
'definitions',
|
||||||
[
|
[
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import { boosterIcons } from './boosterIcons';
|
|||||||
import { camouflageIcons } from './camouflageIcons';
|
import { camouflageIcons } from './camouflageIcons';
|
||||||
import { circleFlags } from './circleFlags';
|
import { circleFlags } from './circleFlags';
|
||||||
import { consumableProvisionIcons } from './consumableProvisionIcons';
|
import { consumableProvisionIcons } from './consumableProvisionIcons';
|
||||||
|
import { currencies } from './currencies';
|
||||||
import { definitions } from './definitions';
|
import { definitions } from './definitions';
|
||||||
import { equipmentIcons } from './equipmentIcons';
|
import { equipmentIcons } from './equipmentIcons';
|
||||||
import { moduleIcons } from './moduleIcons';
|
import { moduleIcons } from './moduleIcons';
|
||||||
@@ -38,6 +39,7 @@ const methods = [
|
|||||||
boosterIcons,
|
boosterIcons,
|
||||||
tankArmors,
|
tankArmors,
|
||||||
tankModels,
|
tankModels,
|
||||||
|
currencies,
|
||||||
];
|
];
|
||||||
|
|
||||||
for (const method of methods) {
|
for (const method of methods) {
|
||||||
|
|||||||
+147
-5
@@ -1,12 +1,15 @@
|
|||||||
import { escapeMarkdown } from 'discord.js';
|
import { escapeMarkdown } from 'discord.js';
|
||||||
import CommandWrapper from '../components/CommandWrapper';
|
import CommandWrapper from '../components/CommandWrapper';
|
||||||
import TitleBar from '../components/TitleBar';
|
import TitleBar from '../components/TitleBar';
|
||||||
|
import { equipmentPriceMatrix } from '../constants/equipmentPrice';
|
||||||
import { getAccountInfo } from '../core/blitz/getAccountInfo';
|
import { getAccountInfo } from '../core/blitz/getAccountInfo';
|
||||||
import { getClanAccountInfo } from '../core/blitz/getClanAccountInfo';
|
import { getClanAccountInfo } from '../core/blitz/getClanAccountInfo';
|
||||||
import getTankStats from '../core/blitz/getTankStats';
|
import getTankStats from '../core/blitz/getTankStats';
|
||||||
import resolveTankId from '../core/blitz/resolveTankId';
|
import resolveTankId from '../core/blitz/resolveTankId';
|
||||||
|
import { asset } from '../core/blitzkrieg/asset';
|
||||||
import { buildTechTreeLine } from '../core/blitzkrieg/buildTechTreeLine';
|
import { buildTechTreeLine } from '../core/blitzkrieg/buildTechTreeLine';
|
||||||
import { emblemIdToURL } from '../core/blitzkrieg/emblemIdToURL';
|
import { emblemIdToURL } from '../core/blitzkrieg/emblemIdToURL';
|
||||||
|
import { iconPng } from '../core/blitzkrieg/iconPng';
|
||||||
import { resolveAncestry } from '../core/blitzkrieg/resolveAncestry';
|
import { resolveAncestry } from '../core/blitzkrieg/resolveAncestry';
|
||||||
import { tankDefinitions } from '../core/blitzkrieg/tankDefinitions';
|
import { tankDefinitions } from '../core/blitzkrieg/tankDefinitions';
|
||||||
import {
|
import {
|
||||||
@@ -54,7 +57,7 @@ export const researchCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (firstOwnedTechTree === undefined) {
|
if (firstOwnedTechTree === undefined) {
|
||||||
return `idk what to call this error lol`;
|
throw new Error('No first owned tech tree found.');
|
||||||
}
|
}
|
||||||
|
|
||||||
const line = (
|
const line = (
|
||||||
@@ -82,6 +85,48 @@ export const researchCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
{await Promise.all(
|
{await Promise.all(
|
||||||
line.map(async (id) => {
|
line.map(async (id) => {
|
||||||
const tank = awaitedTankDefinitions[id];
|
const tank = awaitedTankDefinitions[id];
|
||||||
|
const turretXps = new Map<number, number>();
|
||||||
|
const gunXps = new Map<number, number>();
|
||||||
|
const engineXps = new Map<number, number>();
|
||||||
|
const trackXps = new Map<number, number>();
|
||||||
|
|
||||||
|
tank.turrets.forEach((turret) => {
|
||||||
|
if (turret.xp !== undefined) {
|
||||||
|
turretXps.set(turret.id, turret.xp);
|
||||||
|
}
|
||||||
|
|
||||||
|
turret.guns.forEach((gun) => {
|
||||||
|
if (gun.xp !== undefined) {
|
||||||
|
gunXps.set(gun.id, gun.xp);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
tank.engines.forEach((engine) => {
|
||||||
|
if (engine.xp !== undefined) {
|
||||||
|
engineXps.set(engine.id, engine.xp);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
tank.tracks.forEach((track) => {
|
||||||
|
if (track.xp !== undefined) {
|
||||||
|
trackXps.set(track.id, track.xp);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let moduleXp = 0;
|
||||||
|
turretXps.forEach((value) => {
|
||||||
|
moduleXp += value;
|
||||||
|
});
|
||||||
|
gunXps.forEach((value) => {
|
||||||
|
moduleXp += value;
|
||||||
|
});
|
||||||
|
engineXps.forEach((value) => {
|
||||||
|
moduleXp += value;
|
||||||
|
});
|
||||||
|
trackXps.forEach((value) => {
|
||||||
|
moduleXp += value;
|
||||||
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
@@ -173,14 +218,111 @@ export const researchCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
flex: 1,
|
flex: 1,
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
flexDirection: 'column',
|
flexDirection: 'column',
|
||||||
|
justifyContent: 'center',
|
||||||
gap: 8,
|
gap: 8,
|
||||||
padding: '16px 0',
|
padding: '16px 0',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<span>Research: 144,000</span>
|
<div
|
||||||
<span>Upgrades: 62,000</span>
|
style={{
|
||||||
<span>Purchase: 1,500,000</span>
|
display: 'flex',
|
||||||
<span>Equipment: 450,000</span>
|
gap: 4,
|
||||||
|
alignItems: 'center',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
src={await iconPng(asset('icons/currencies/xp.webp'))}
|
||||||
|
width={16}
|
||||||
|
height={16}
|
||||||
|
/>
|
||||||
|
<span
|
||||||
|
style={{
|
||||||
|
fontSize: 16,
|
||||||
|
color: theme.colors.textHighContrast,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Research:{' '}
|
||||||
|
{tank.xp?.toLocaleString(interaction.locale)}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{moduleXp > 0 && (
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
display: 'flex',
|
||||||
|
gap: 4,
|
||||||
|
alignItems: 'center',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
src={await iconPng(
|
||||||
|
asset('icons/currencies/free-xp.webp'),
|
||||||
|
)}
|
||||||
|
width={16}
|
||||||
|
height={16}
|
||||||
|
/>
|
||||||
|
<span
|
||||||
|
style={{
|
||||||
|
fontSize: 16,
|
||||||
|
color: theme.colors.textHighContrast,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Upgrades: {moduleXp.toLocaleString()}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
display: 'flex',
|
||||||
|
gap: 4,
|
||||||
|
alignItems: 'center',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
src={await iconPng(
|
||||||
|
asset('icons/currencies/silver.webp'),
|
||||||
|
)}
|
||||||
|
width={16}
|
||||||
|
height={16}
|
||||||
|
/>
|
||||||
|
<span
|
||||||
|
style={{
|
||||||
|
fontSize: 16,
|
||||||
|
color: theme.colors.textHighContrast,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Purchase:{' '}
|
||||||
|
{tank.price.value.toLocaleString(interaction.locale)}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
display: 'flex',
|
||||||
|
gap: 4,
|
||||||
|
alignItems: 'center',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
src={await iconPng(
|
||||||
|
asset('icons/currencies/silver.webp'),
|
||||||
|
)}
|
||||||
|
width={16}
|
||||||
|
height={16}
|
||||||
|
/>
|
||||||
|
<span
|
||||||
|
style={{
|
||||||
|
fontSize: 16,
|
||||||
|
color: theme.colors.textHighContrast,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Equipment:{' '}
|
||||||
|
{equipmentPriceMatrix[tank.tier]
|
||||||
|
.reduce((a, b) => a + 3 * b, 0)
|
||||||
|
.toLocaleString(interaction.locale)}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
import { Vector3Tuple } from 'three';
|
||||||
|
import { Tier } from '../core/blitzkrieg/tankDefinitions';
|
||||||
|
|
||||||
|
export const equipmentPriceMatrix: Record<Tier, Vector3Tuple> = {
|
||||||
|
1: [100, 200, 300],
|
||||||
|
2: [200, 300, 400],
|
||||||
|
3: [400, 500, 600],
|
||||||
|
4: [4000, 5000, 6000],
|
||||||
|
5: [40_000, 50_000, 60_000],
|
||||||
|
6: [100_000, 120_000, 140_000],
|
||||||
|
7: [150_000, 170_000, 190_000],
|
||||||
|
8: [200_000, 225_000, 250_000],
|
||||||
|
9: [250_000, 275_000, 300_000],
|
||||||
|
10: [300_000, 350_000, 400_000],
|
||||||
|
};
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
import sharp from 'sharp';
|
||||||
|
|
||||||
|
const cache: Record<string, string> = {};
|
||||||
|
|
||||||
|
export async function iconPng(url: string) {
|
||||||
|
if (cache[url]) return cache[url];
|
||||||
|
|
||||||
|
const imageResponse = await fetch(url);
|
||||||
|
const imageBufferWEBP = await imageResponse.arrayBuffer();
|
||||||
|
const imageBufferPNG = await sharp(imageBufferWEBP).png().toBuffer();
|
||||||
|
cache[url] = `data:image/png;base64,${imageBufferPNG.toString('base64')}`;
|
||||||
|
|
||||||
|
return cache[url];
|
||||||
|
}
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
|
import { readFile } from 'fs/promises';
|
||||||
import { deburr } from 'lodash';
|
import { deburr } from 'lodash';
|
||||||
import { Vector2Tuple } from 'three';
|
import { Vector2Tuple } from 'three';
|
||||||
import { TankClass, TreeType } from '../../../components/Tanks';
|
import { TankClass, TreeType } from '../../../components/Tanks';
|
||||||
import { asset } from '../asset';
|
import { superDecompress } from '../superDecompress';
|
||||||
import { fetchCdonLz4 } from '../fetchCdonLz4';
|
|
||||||
import { TIERS } from './constants';
|
import { TIERS } from './constants';
|
||||||
|
|
||||||
export type ShellType = 'ap' | 'ap_cr' | 'hc' | 'he';
|
export type ShellType = 'ap' | 'ap_cr' | 'hc' | 'he';
|
||||||
@@ -142,14 +142,14 @@ export type ShellDefinition = {
|
|||||||
explosionRadius?: number;
|
explosionRadius?: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const tankDefinitions = fetchCdonLz4<TankDefinitions>(
|
// export const tankDefinitions = fetchCdonLz4<TankDefinitions>(
|
||||||
asset('definitions/tanks.cdon.lz4'),
|
// asset('definitions/tanks.cdon.lz4'),
|
||||||
);
|
|
||||||
|
|
||||||
// export const tankDefinitions = readFile('test.tanks.cdon.lz4').then((data) =>
|
|
||||||
// superDecompress<TankDefinitions>(data.buffer),
|
|
||||||
// );
|
// );
|
||||||
|
|
||||||
|
export const tankDefinitions = readFile('test.tanks.cdon.lz4').then((data) =>
|
||||||
|
superDecompress<TankDefinitions>(data.buffer),
|
||||||
|
);
|
||||||
|
|
||||||
const entries = new Promise<TankDefinition[]>(async (resolve) => {
|
const entries = new Promise<TankDefinition[]>(async (resolve) => {
|
||||||
resolve(Object.entries(await tankDefinitions).map(([, entry]) => entry));
|
resolve(Object.entries(await tankDefinitions).map(([, entry]) => entry));
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,9 +1,6 @@
|
|||||||
import sharp from 'sharp';
|
import { iconPng } from './iconPng';
|
||||||
import { tankIcon } from './tankIcon';
|
import { tankIcon } from './tankIcon';
|
||||||
|
|
||||||
export async function tankIconPng(id: number) {
|
export function tankIconPng(id: number) {
|
||||||
const imageResponse = await fetch(tankIcon(id));
|
return iconPng(tankIcon(id));
|
||||||
const imageBufferWEBP = await imageResponse.arrayBuffer();
|
|
||||||
const imageBufferPNG = await sharp(imageBufferWEBP).png().toBuffer();
|
|
||||||
return `data:image/png;base64,${imageBufferPNG.toString('base64')}`;
|
|
||||||
}
|
}
|
||||||
Reference in new issue
Block a user