mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-21 02:37:05 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0368e9ceda | ||
|
|
28f365f762 | ||
|
|
40a81f6b1b | ||
|
|
9475d22472 | ||
|
|
9538a03afb | ||
|
|
d5d171bea6 | ||
|
|
a9c9a90ac1 | ||
|
|
f7c562f8b6 | ||
|
|
836cf69f01 | ||
|
|
ba17aae706 | ||
|
|
30ca5c053a | ||
|
|
c36419f5b6 | ||
|
|
1879895db2 | ||
|
|
c964e3c8ec | ||
|
|
2ef6d18f82 | ||
|
|
10b672572b | ||
|
|
2a4efa8cd2 | ||
|
|
5a8435da29 | ||
|
|
3461349a96 | ||
|
|
3791e9df12 | ||
|
|
b3c36aac93 | ||
|
|
c0895409bc | ||
|
|
438b565cbb | ||
|
|
cf1a82e89b | ||
|
|
0506e361b2 | ||
|
|
d6a1357a82 | ||
|
|
a5a1dbd51b | ||
|
|
5201350e44 | ||
|
|
6a84b9d5ae |
No files matched your search
@@ -27,3 +27,4 @@ target
|
||||
/.vercel
|
||||
/.astro
|
||||
.vercel
|
||||
/src
|
||||
@@ -0,0 +1,7 @@
|
||||
# BlitzKit 1.27.2
|
||||
|
||||
This update only affects the website.
|
||||
|
||||
## Fixes
|
||||
|
||||
- The new Improved Vertical Stabilizer equipment which only affects the gun depression found on the Type 63 now works
|
||||
@@ -0,0 +1,9 @@
|
||||
# BlitzKit 1.27.3
|
||||
|
||||
This update only affects the bot.
|
||||
|
||||
## Fixes
|
||||
|
||||
- Added support for 64-bit IDs allowing users with new accounts to link with BlitzKit
|
||||
- This comes at the added cost of resetting the links of all other accounts
|
||||
- Just re-link and you're good to go
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "blitzkit",
|
||||
"private": true,
|
||||
"version": "1.27.1",
|
||||
"version": "1.27.4",
|
||||
"description": "🎉 Tools for everything World of Tanks Blitz",
|
||||
"type": "module",
|
||||
"types": "./types.d.ts",
|
||||
|
||||
@@ -17,7 +17,7 @@ export const debugCommand = new Promise<CommandRegistry>((resolve) => {
|
||||
const list = [
|
||||
[strings.bot.commands.debug.body.version, packageJSON.version],
|
||||
[
|
||||
strings.bot.commands.debug.body.shard,
|
||||
strings.bot.commands.debug.body.shard.label,
|
||||
client.shard?.ids[0] ?? strings.bot.commands.debug.body.shard.default,
|
||||
],
|
||||
[
|
||||
|
||||
@@ -17,7 +17,6 @@ export function CommandWrapper({ children, fat }: CommandWrapperProps) {
|
||||
width: '100%',
|
||||
color: theme.colors.textHighContrast,
|
||||
position: 'relative',
|
||||
background: theme.colors.appBackground1,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
|
||||
@@ -8,12 +8,12 @@ export async function filtersToDescription(
|
||||
{ nation, tier, type, class: tankClass, tank }: StatFilters,
|
||||
locale: Locale,
|
||||
) {
|
||||
const { strings } = translator(locale);
|
||||
const { strings, bkLocale } = translator(locale);
|
||||
const awaitedTankDefinitions = await fetchTankDefinitions();
|
||||
const info: string[] = [];
|
||||
|
||||
// TODO: somehow localize tank names?
|
||||
if (tank) return awaitedTankDefinitions.tanks[tank].name;
|
||||
if (tank) return awaitedTankDefinitions.tanks[tank].name.locales[bkLocale];
|
||||
if (nation)
|
||||
info.push((strings.common.nations as Record<string, string>)[nation]);
|
||||
if (tier) {
|
||||
|
||||
@@ -8,6 +8,8 @@ export async function getBlitzFromDiscord(discordId: bigint) {
|
||||
|
||||
if (unique === null) return null;
|
||||
|
||||
await flagUserActivity(unique.blitz_id);
|
||||
return { id: unique.blitz_id, region: idToRegion(unique.blitz_id) };
|
||||
const id = Number(unique.blitz_id);
|
||||
|
||||
await flagUserActivity(id);
|
||||
return { id, region: idToRegion(id) };
|
||||
}
|
||||
@@ -3,7 +3,8 @@ import { Locale } from 'discord.js';
|
||||
import { SUPPORTED_LOCALES_DISCORD } from '../localization/strings/constants';
|
||||
import { translator } from '../localization/translator';
|
||||
|
||||
const validNameRegex = /^[-_\p{L}\p{N}\p{sc=Deva}\p{sc=Thai}]{1,32}$/u;
|
||||
const validNameRegex =
|
||||
/^[\p{Ll}\p{Lm}\p{Lo}\p{N}\p{sc=Devanagari}\p{sc=Thai}_-]+$/u;
|
||||
|
||||
export function localizationObject(
|
||||
path: (strings: BlitzKitStrings) => string,
|
||||
@@ -14,7 +15,8 @@ export function localizationObject(
|
||||
(localizations, locale) => {
|
||||
const { strings } = translator(locale);
|
||||
const translation = literalsFunc(path(strings), literals);
|
||||
const isValid = !strict || validNameRegex.test(translation);
|
||||
const isValid =
|
||||
(!strict || validNameRegex.test(translation)) && translation.length > 0;
|
||||
|
||||
if (!isValid) {
|
||||
console.warn(
|
||||
|
||||
@@ -1,64 +0,0 @@
|
||||
import {
|
||||
ActionRowBuilder,
|
||||
AttachmentBuilder,
|
||||
ButtonBuilder,
|
||||
EmbedBuilder,
|
||||
InteractionEditReplyOptions,
|
||||
InteractionReplyOptions,
|
||||
MessageEditOptions,
|
||||
} from 'discord.js';
|
||||
import { InteractionReturnable } from '../../events/interactionCreate';
|
||||
import { Writeable } from '../../types/writable';
|
||||
import { jsxToPngThreaded } from '../blitzkit/jsxToPngThreaded';
|
||||
import { RenderConfiguration } from '../blitzkit/renderConfiguration';
|
||||
|
||||
export async function normalizeInteractionReturnable(
|
||||
returnable: InteractionReturnable,
|
||||
) {
|
||||
const images: [number, Buffer][] = [];
|
||||
const reply: InteractionEditReplyOptions &
|
||||
InteractionReplyOptions &
|
||||
MessageEditOptions = {};
|
||||
const awaitedReturnable = await returnable;
|
||||
const normalizedReturnable = Array.isArray(awaitedReturnable)
|
||||
? awaitedReturnable
|
||||
: [awaitedReturnable];
|
||||
let renderConfiguration = new RenderConfiguration();
|
||||
|
||||
await Promise.all(
|
||||
normalizedReturnable.map(async (item, index) => {
|
||||
if (typeof item === 'string') {
|
||||
reply.content = item;
|
||||
} else if (item instanceof EmbedBuilder) {
|
||||
if (!reply.embeds) reply.embeds = [];
|
||||
(reply.embeds as Writeable<typeof reply.embeds>).push(item);
|
||||
} else if (item instanceof ButtonBuilder) {
|
||||
if (!reply.components)
|
||||
reply.components = [new ActionRowBuilder<ButtonBuilder>()];
|
||||
(reply.components[0] as ActionRowBuilder<ButtonBuilder>).addComponents(
|
||||
item,
|
||||
);
|
||||
} else if (item instanceof AttachmentBuilder) {
|
||||
if (!reply.files) reply.files = [];
|
||||
(reply.files as Writeable<typeof reply.files>).push(item);
|
||||
} else if (item instanceof RenderConfiguration) {
|
||||
renderConfiguration = item;
|
||||
} else if (item === null) {
|
||||
return;
|
||||
} else {
|
||||
const image = await jsxToPngThreaded(item, renderConfiguration);
|
||||
images.push([index, image]);
|
||||
}
|
||||
}),
|
||||
);
|
||||
|
||||
if (images.length > 0) {
|
||||
images.sort(([a], [b]) => b - a);
|
||||
if (!reply.files) reply.files = [];
|
||||
images.forEach(([, image]) =>
|
||||
(reply.files as Writeable<typeof reply.files>)?.push(image),
|
||||
);
|
||||
}
|
||||
|
||||
return reply;
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
import { imgur, isFunny } from '@blitzkit/core';
|
||||
import {
|
||||
ActionRowBuilder,
|
||||
AttachmentBuilder,
|
||||
ButtonBuilder,
|
||||
EmbedBuilder,
|
||||
InteractionEditReplyOptions,
|
||||
InteractionReplyOptions,
|
||||
MessageEditOptions,
|
||||
} from 'discord.js';
|
||||
import { InteractionReturnable } from '../../events/interactionCreate';
|
||||
import { theme } from '../../stitches.config';
|
||||
import { Writeable } from '../../types/writable';
|
||||
import { jsxToPngThreaded } from '../blitzkit/jsxToPngThreaded';
|
||||
import { RenderConfiguration } from '../blitzkit/renderConfiguration';
|
||||
|
||||
export async function normalizeInteractionReturnable(
|
||||
returnable: InteractionReturnable,
|
||||
) {
|
||||
const images: [number, Buffer][] = [];
|
||||
const reply: InteractionEditReplyOptions &
|
||||
InteractionReplyOptions &
|
||||
MessageEditOptions = {};
|
||||
const awaitedReturnable = await returnable;
|
||||
const normalizedReturnable = Array.isArray(awaitedReturnable)
|
||||
? awaitedReturnable
|
||||
: [awaitedReturnable];
|
||||
let renderConfiguration = new RenderConfiguration();
|
||||
|
||||
await Promise.all(
|
||||
normalizedReturnable.map(async (item, index) => {
|
||||
if (typeof item === 'string') {
|
||||
reply.content = item;
|
||||
} else if (item instanceof EmbedBuilder) {
|
||||
if (!reply.embeds) reply.embeds = [];
|
||||
(reply.embeds as Writeable<typeof reply.embeds>).push(item);
|
||||
} else if (item instanceof ButtonBuilder) {
|
||||
if (!reply.components)
|
||||
reply.components = [new ActionRowBuilder<ButtonBuilder>()];
|
||||
(reply.components[0] as ActionRowBuilder<ButtonBuilder>).addComponents(
|
||||
item,
|
||||
);
|
||||
} else if (item instanceof AttachmentBuilder) {
|
||||
if (!reply.files) reply.files = [];
|
||||
(reply.files as Writeable<typeof reply.files>).push(item);
|
||||
} else if (item instanceof RenderConfiguration) {
|
||||
renderConfiguration = item;
|
||||
} else if (item === null) {
|
||||
return;
|
||||
} else {
|
||||
let jsx: JSX.Element;
|
||||
|
||||
if (isFunny()) {
|
||||
const angle = (Math.random() * 2 - 1) * 10;
|
||||
jsx = (
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
transform: `rotate(${angle}deg)`,
|
||||
backgroundColor: theme.colors.appBackground1,
|
||||
position: 'relative',
|
||||
}}
|
||||
>
|
||||
{item}
|
||||
|
||||
<img
|
||||
src={imgur('MWEny5u')}
|
||||
style={{
|
||||
display: 'block',
|
||||
position: 'absolute',
|
||||
top: 250,
|
||||
left: '10%',
|
||||
width: 100,
|
||||
transform: 'translateY(-50%)',
|
||||
backgroundSize: 'contain',
|
||||
backgroundRepeat: 'no-repeat',
|
||||
zIndex: 3,
|
||||
}}
|
||||
/>
|
||||
|
||||
<img
|
||||
src={imgur('SboPMXY')}
|
||||
style={{
|
||||
position: 'absolute',
|
||||
top: 280,
|
||||
width: 80,
|
||||
left: '50%',
|
||||
transform: 'translate(-50%, -50%)',
|
||||
}}
|
||||
/>
|
||||
|
||||
<img
|
||||
src={imgur('MWEny5u')}
|
||||
style={{
|
||||
display: 'block',
|
||||
position: 'absolute',
|
||||
top: 250,
|
||||
right: '10%',
|
||||
width: 100,
|
||||
transform: 'translateY(-50%)',
|
||||
backgroundSize: 'contain',
|
||||
backgroundRepeat: 'no-repeat',
|
||||
zIndex: 3,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
} else {
|
||||
jsx = (
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
position: 'relative',
|
||||
backgroundColor: theme.colors.appBackground1,
|
||||
}}
|
||||
>
|
||||
{item}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const image = await jsxToPngThreaded(jsx, renderConfiguration);
|
||||
images.push([index, image]);
|
||||
}
|
||||
}),
|
||||
);
|
||||
|
||||
if (images.length > 0) {
|
||||
images.sort(([a], [b]) => b - a);
|
||||
if (!reply.files) reply.files = [];
|
||||
images.forEach(([, image]) =>
|
||||
(reply.files as Writeable<typeof reply.files>)?.push(image),
|
||||
);
|
||||
}
|
||||
|
||||
return reply;
|
||||
}
|
||||
@@ -12,8 +12,9 @@ export function translator(localeRaw: Locale) {
|
||||
SUPPORTED_LOCALES_DISCORD.includes(localeRaw)
|
||||
? localeRaw
|
||||
: DEFAULT_LOCALE_DISCORD;
|
||||
const strings = STRINGS[SUPPORTED_LOCALES_DISCORD_MAP_INVERSE[locale]];
|
||||
const unwrap = unwrapper(SUPPORTED_LOCALES_DISCORD_MAP_INVERSE[locale]);
|
||||
const bkLocale = SUPPORTED_LOCALES_DISCORD_MAP_INVERSE[locale];
|
||||
const strings = STRINGS[bkLocale];
|
||||
const unwrap = unwrapper(bkLocale);
|
||||
|
||||
return { locale, strings, unwrap };
|
||||
return { locale, strings, unwrap, bkLocale };
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
import { isFunny } from '@blitzkit/core';
|
||||
import {
|
||||
ActionRowBuilder,
|
||||
AttachmentBuilder,
|
||||
@@ -16,14 +17,42 @@ import { psa } from '../../../core/discord/psa';
|
||||
import { translator } from '../../../core/localization/translator';
|
||||
import { Writeable } from '../../../types/writable';
|
||||
|
||||
const funnyResponses = [
|
||||
"your dwecisions were calculawed buw man, you're bad at math 🥀🥀",
|
||||
'senpai, have you consiwered not lacking 😳',
|
||||
'let shoow a guess cutie... it was your team? 🤬🤬🤬',
|
||||
'confiwence is key. unforwunawely you lost whe lock 🔒💔',
|
||||
"when they say live green, they dwn't mean your 🌳 winrate 🌳",
|
||||
'daddy viewing your swats, hewe? you really are brawe 😎',
|
||||
'no surrie! your numwers are swill 💔',
|
||||
"i would giwe you awvice, you won'w understand 🥀🥀",
|
||||
"i diwn'w beliewe in negawive numwers unwil i saw your stats 😳😳😳",
|
||||
'yeah daddy, use me more 🤤',
|
||||
'uwu, hewe are your swaws... uwu 😋😋😋',
|
||||
'hehehehe it tickles 😻',
|
||||
'yeeeeeeeeeeeeahhhhhh that hits the spot 😳',
|
||||
'ooooh yesss my circuits are starting to hurt yeeeeeeee 💥',
|
||||
'wawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawawaw',
|
||||
'https://tenor.com/tre3NETle2e.gif',
|
||||
];
|
||||
|
||||
export async function handleChatInputCommand(
|
||||
interaction: ChatInputCommandInteraction<CacheType>,
|
||||
) {
|
||||
await interaction.deferReply();
|
||||
|
||||
if (isFunny()) {
|
||||
const response =
|
||||
funnyResponses[Math.floor(Math.random() * funnyResponses.length)];
|
||||
const waitTime = response.length * 60;
|
||||
|
||||
await interaction.editReply(response);
|
||||
await new Promise((resolve) => setTimeout(resolve, waitTime));
|
||||
}
|
||||
|
||||
const awaitedCommands = await commands;
|
||||
const registry = awaitedCommands[interaction.commandName];
|
||||
|
||||
await interaction.deferReply();
|
||||
|
||||
try {
|
||||
const returnable = await registry.handler(interaction);
|
||||
|
||||
|
||||
@@ -15,7 +15,6 @@ import {
|
||||
SlashCommandSubcommandsOnlyBuilder,
|
||||
} from 'discord.js';
|
||||
import { aboutCommand } from '../../commands/about';
|
||||
import { auctionCommand } from '../../commands/auction';
|
||||
import { breakdownCommand } from '../../commands/breakdown';
|
||||
import { debugCommand } from '../../commands/debug';
|
||||
import { evolutionCommand } from '../../commands/evolution';
|
||||
@@ -80,7 +79,7 @@ interface CommandRegistryExplicit extends CommandRegistryBase {
|
||||
export type CommandRegistry = CommandRegistryImplicit | CommandRegistryExplicit;
|
||||
|
||||
export const COMMANDS_RAW: Promise<CommandRegistry>[] = [
|
||||
auctionCommand,
|
||||
// auctionCommand,
|
||||
permissionsCommand,
|
||||
debugCommand,
|
||||
aboutCommand,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { assertSecret } from '@blitzkit/core';
|
||||
import { assertSecret, isFunny } from '@blitzkit/core';
|
||||
import { ActivityType, ShardingManager } from 'discord.js';
|
||||
import {
|
||||
discoveredIdsDefinitions,
|
||||
@@ -45,7 +45,7 @@ const interval = setInterval(async () => {
|
||||
const usernames = awaitedDiscoveredIdsDefinitions.count;
|
||||
|
||||
manager.broadcastEval(
|
||||
(client, { servers, users, channels, tanks, usernames }) => {
|
||||
async (client, { servers, users, channels, tanks, usernames }) => {
|
||||
const bios = [
|
||||
`Living in ${servers.toLocaleString()} servers`,
|
||||
`Serving ${users.toLocaleString()} users`,
|
||||
@@ -62,6 +62,13 @@ const interval = setInterval(async () => {
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
for (const guild of client.guilds.cache.values()) {
|
||||
try {
|
||||
const botMember = await guild.members.fetch(client.user.id);
|
||||
await botMember.setNickname(isFunny ? 'FreakKit' : 'BlitzKit');
|
||||
} catch {}
|
||||
}
|
||||
},
|
||||
{ context: { servers, channels, users, tanks, usernames } },
|
||||
);
|
||||
|
||||
@@ -18,12 +18,27 @@ import {
|
||||
} from '@radix-ui/colors';
|
||||
import { createBorderStyles, createColors, createSpaces } from 'bepaint';
|
||||
|
||||
const funnyColors = {
|
||||
pink1: crimsonDark.crimson5,
|
||||
pink2: crimsonDark.crimson5,
|
||||
pink3: crimsonDark.crimson5,
|
||||
pink4: crimsonDark.crimson6,
|
||||
pink5: crimsonDark.crimson6,
|
||||
pink6: crimsonDark.crimson7,
|
||||
pink7: crimsonDark.crimson7,
|
||||
pink8: crimsonDark.crimson8,
|
||||
pink9: crimsonDark.crimson9,
|
||||
pink10: crimsonDark.crimson10,
|
||||
pink11: crimsonDark.crimson11,
|
||||
pink12: crimsonDark.crimson12,
|
||||
};
|
||||
|
||||
// this isn't really a stitches config, but the object is compliant
|
||||
export const theme = {
|
||||
spaces: createSpaces(),
|
||||
|
||||
colors: {
|
||||
...createColors(slateDark),
|
||||
...createColors(funnyColors),
|
||||
...createColors(slateDarkA, 'alpha'),
|
||||
...createColors(slate, 'light'),
|
||||
|
||||
|
||||
@@ -44,6 +44,7 @@ export * from './unwrapBlitzkitResponse';
|
||||
export * from './votes';
|
||||
// export * from './withCORSProxy';
|
||||
export * from './createDefaultProvisions';
|
||||
export * from './isFunny';
|
||||
export * from './metaSortTank';
|
||||
export * from './romanize';
|
||||
export * from './youtubers';
|
||||
@@ -0,0 +1,17 @@
|
||||
const FUNNY_DATES: [number, number][] = [
|
||||
[4, 1],
|
||||
[4, 2],
|
||||
[4, 3],
|
||||
];
|
||||
|
||||
export function isFunny() {
|
||||
return true;
|
||||
|
||||
const now = new Date();
|
||||
|
||||
return (
|
||||
FUNNY_DATES.some(
|
||||
([month, day]) => now.getMonth() === month - 1 && now.getDate() === day,
|
||||
) || import.meta.env.DEBUG_FUNNY === 'true'
|
||||
);
|
||||
}
|
||||
@@ -26,8 +26,10 @@ export async function fetchTankNames() {
|
||||
searchableName: tank.name_full ?? tank.name,
|
||||
searchableNameDeburr,
|
||||
camouflages: tank.camouflages
|
||||
?.map((id) => camouflageDefinitions.camouflages[id]?.name)
|
||||
?.map((id) => SUPPORTED_LOCALES.map((locale) => camouflageDefinitions.camouflages[id]?.name.locales[locale]))
|
||||
.flat()
|
||||
.filter(Boolean)
|
||||
.map(deburr)
|
||||
.join(' '),
|
||||
treeType: tank.type,
|
||||
};
|
||||
|
||||
+498
-1200
File diff suppressed because it is too large.
Load diff
+1148
-498
File diff suppressed because it is too large.
Load diff
+1148
-498
File diff suppressed because it is too large.
Load diff
+1120
-528
File diff suppressed because it is too large.
Load diff
+1082
-684
File diff suppressed because it is too large.
Load diff
+387
-1405
File diff suppressed because it is too large.
Load diff
+1148
-498
File diff suppressed because it is too large.
Load diff
+1134
-754
File diff suppressed because it is too large.
Load diff
@@ -1,5 +1,4 @@
|
||||
import { assertSecret } from '@blitzkit/core';
|
||||
import { existsSync } from 'fs';
|
||||
import { mkdir, writeFile } from 'fs/promises';
|
||||
import { parse as parsePath } from 'path';
|
||||
import ProgressBar from 'progress';
|
||||
@@ -57,9 +56,12 @@ while (true) {
|
||||
console.warn(`Failed to make directory "${dir}"`);
|
||||
}
|
||||
|
||||
const isDvpl = path.endsWith('.dvpl');
|
||||
const buffer = Buffer.from(data);
|
||||
|
||||
await writeFile(
|
||||
`${DATA}/${path}`,
|
||||
new Uint8Array(writeDVPL(Buffer.from(data))),
|
||||
`${DATA}/${path}${isDvpl ? '' : '.dvpl'}`,
|
||||
new Uint8Array(isDvpl ? buffer : writeDVPL(buffer)),
|
||||
);
|
||||
|
||||
bar.tick();
|
||||
|
||||
@@ -6,7 +6,7 @@ import { TextureMutation } from './constants';
|
||||
|
||||
export async function readTexture(path: string, mutation?: TextureMutation) {
|
||||
const ddsTexturePath = path.replace('.tex', '.dx11.dds');
|
||||
const isDds = existsSync(ddsTexturePath);
|
||||
const isDds = existsSync(`${ddsTexturePath}.dvpl`);
|
||||
const resolvedTexturePath = isDds
|
||||
? ddsTexturePath
|
||||
: ddsTexturePath.replace('.dds', '.pvr');
|
||||
|
||||
@@ -30,10 +30,7 @@ export async function commitMultipleFiles(
|
||||
} else if (response.status === 200) {
|
||||
const buffer = Buffer.from(await response.arrayBuffer());
|
||||
|
||||
// we discard blob if they're the same size; it's unlikely their
|
||||
// contents will be different; I love playing russian roulette!
|
||||
const equal = buffer.length === change.content.length || buffer.equals(change.content);
|
||||
if (!equal) {
|
||||
if (!buffer.equals(change.content)) {
|
||||
const diff = change.content.length - buffer.length;
|
||||
|
||||
console.log(
|
||||
|
||||
@@ -8,7 +8,7 @@ import { writeFile } from 'fs/promises';
|
||||
const ROOT = '@blitzkit/i18n/strings';
|
||||
const WORKING_ROOT = '../../packages/i18n/strings';
|
||||
|
||||
const defaultStrings = await import(`${ROOT}/${DEFAULT_LOCALE}.json`);
|
||||
const defaultStrings = require(`${ROOT}/${DEFAULT_LOCALE}.json`).default;
|
||||
const nonDefaultLocales = SUPPORTED_LOCALES.filter(
|
||||
(locale) => locale !== DEFAULT_LOCALE,
|
||||
);
|
||||
@@ -19,9 +19,13 @@ function prune(defaultStrings: TranslationTree, strings: TranslationTree) {
|
||||
if (typeof defaultStrings[key] === typeof strings[key]) {
|
||||
if (typeof strings[key] === 'string') {
|
||||
if (
|
||||
// are equivalent regardless of %s flavor
|
||||
(defaultStrings[key] as string).replaceAll(/%s\d/g, '%s') ===
|
||||
(strings[key] as string).replaceAll(/%s\d/g, '%s') ||
|
||||
strings[key] === ''
|
||||
// string is empty
|
||||
strings[key] === '' ||
|
||||
// string has old flavor of %s
|
||||
strings[key].match(/%s([^\d]|$)/g) !== null
|
||||
) {
|
||||
delete strings[key];
|
||||
}
|
||||
@@ -42,7 +46,7 @@ function prune(defaultStrings: TranslationTree, strings: TranslationTree) {
|
||||
for (const locale of nonDefaultLocales) {
|
||||
console.log(`Pruning ${locale}...`);
|
||||
|
||||
const strings = await import(`${ROOT}/${locale}.json`);
|
||||
const strings = require(`${ROOT}/${locale}.json`).default;
|
||||
const pruned = prune(defaultStrings, strings);
|
||||
|
||||
writeFile(`${WORKING_ROOT}/${locale}.json`, JSON.stringify(pruned, null, 2));
|
||||
|
||||
@@ -180,6 +180,11 @@ export const StaticArmor = memo<ArmorSceneProps>(({ thicknessRange }) => {
|
||||
duel.protagonist.tank.equipment_preset,
|
||||
duel.protagonist.equipmentMatrix,
|
||||
);
|
||||
const hasDownImprovedVerticalStabilizer = await hasEquipment(
|
||||
124,
|
||||
duel.protagonist.tank.equipment_preset,
|
||||
duel.protagonist.equipmentMatrix,
|
||||
);
|
||||
const boundingRect = canvas.getBoundingClientRect();
|
||||
|
||||
delta.set(event.clientX, event.clientY).sub(position);
|
||||
@@ -191,6 +196,7 @@ export const StaticArmor = memo<ArmorSceneProps>(({ thicknessRange }) => {
|
||||
gunModelDefinition.pitch,
|
||||
turretModelDefinition.yaw,
|
||||
hasImprovedVerticalStabilizer,
|
||||
hasDownImprovedVerticalStabilizer,
|
||||
);
|
||||
modelTransformEvent.emit({ pitch, yaw });
|
||||
}
|
||||
@@ -275,6 +281,11 @@ export const StaticArmor = memo<ArmorSceneProps>(({ thicknessRange }) => {
|
||||
duel.protagonist.tank.equipment_preset,
|
||||
duel.protagonist.equipmentMatrix,
|
||||
);
|
||||
const hasDownImprovedVerticalStabilizer = await hasEquipment(
|
||||
124,
|
||||
duel.protagonist.tank.equipment_preset,
|
||||
duel.protagonist.equipmentMatrix,
|
||||
);
|
||||
const boundingRect = canvas.getBoundingClientRect();
|
||||
delta.set(event.clientX, event.clientY).sub(position);
|
||||
position.set(event.clientX, event.clientY);
|
||||
@@ -285,6 +296,7 @@ export const StaticArmor = memo<ArmorSceneProps>(({ thicknessRange }) => {
|
||||
gunModelDefinition.pitch,
|
||||
turretModelDefinition.yaw,
|
||||
hasImprovedVerticalStabilizer,
|
||||
hasDownImprovedVerticalStabilizer,
|
||||
);
|
||||
modelTransformEvent.emit({ pitch, yaw });
|
||||
}
|
||||
@@ -357,6 +369,11 @@ export const StaticArmor = memo<ArmorSceneProps>(({ thicknessRange }) => {
|
||||
duel.protagonist.tank.equipment_preset,
|
||||
duel.protagonist.equipmentMatrix,
|
||||
);
|
||||
const hasDownImprovedVerticalStabilizer = await hasEquipment(
|
||||
124,
|
||||
duel.protagonist.tank.equipment_preset,
|
||||
duel.protagonist.equipmentMatrix,
|
||||
);
|
||||
const boundingRect = canvas.getBoundingClientRect();
|
||||
delta.set(event.clientX, event.clientY).sub(position);
|
||||
position.set(event.clientX, event.clientY);
|
||||
@@ -367,6 +384,7 @@ export const StaticArmor = memo<ArmorSceneProps>(({ thicknessRange }) => {
|
||||
gunModelDefinition.pitch,
|
||||
turretModelDefinition.yaw,
|
||||
hasImprovedVerticalStabilizer,
|
||||
hasDownImprovedVerticalStabilizer,
|
||||
);
|
||||
modelTransformEvent.emit({ pitch, yaw });
|
||||
}
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
<script>
|
||||
function funnify() {
|
||||
document.body.querySelectorAll('*').forEach((element) => {
|
||||
element.childNodes.forEach((node) => {
|
||||
if (node.nodeType !== 3 || !node.textContent) return;
|
||||
|
||||
node.textContent = node.textContent
|
||||
.replaceAll(/[tdkqgp]/g, 'w')
|
||||
.replaceAll(/[TDKQGP]/g, 'W');
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
funnify();
|
||||
setInterval(funnify, 1000);
|
||||
|
||||
let mouseDown = false;
|
||||
|
||||
document.addEventListener('mousedown', () => (mouseDown = true));
|
||||
document.addEventListener('mouseup', () => (mouseDown = false));
|
||||
|
||||
document.addEventListener('mousemove', (e) => {
|
||||
if (mouseDown) return;
|
||||
|
||||
const star = document.createElement('div');
|
||||
star.classList.add('star');
|
||||
star.innerHTML = '⭐';
|
||||
document.body.appendChild(star);
|
||||
|
||||
star.style.left = `${e.clientX}px`;
|
||||
star.style.top = `${e.clientY}px`;
|
||||
|
||||
setTimeout(() => {
|
||||
star.remove();
|
||||
}, 600);
|
||||
});
|
||||
</script>
|
||||
+3
-1
@@ -107,6 +107,7 @@ export function Characteristics() {
|
||||
const hasSupercharger = useEquipment(107);
|
||||
const hasCalibratedShells = useEquipment(103);
|
||||
const hasImprovedVerticalStabilizer = useEquipment(122);
|
||||
const hasDownImprovedVerticalStabilizer = useEquipment(124);
|
||||
const penetrationCoefficient = coefficient([
|
||||
hasCalibratedShells,
|
||||
resolvePenetrationCoefficient(true, shell.type) - 1,
|
||||
@@ -129,9 +130,10 @@ export function Characteristics() {
|
||||
gunModelDefinition.pitch,
|
||||
turretModelDefinition.yaw,
|
||||
hasImprovedVerticalStabilizer,
|
||||
hasDownImprovedVerticalStabilizer,
|
||||
);
|
||||
});
|
||||
}, [hasImprovedVerticalStabilizer]);
|
||||
}, [hasImprovedVerticalStabilizer, hasDownImprovedVerticalStabilizer]);
|
||||
|
||||
return (
|
||||
<Flex
|
||||
|
||||
+3
@@ -25,6 +25,7 @@ export function QuickInputs() {
|
||||
const initialGunPitch =
|
||||
tankModelDefinition.initial_turret_rotation?.pitch ?? 0;
|
||||
const hasImprovedVerticalStabilizer = useEquipment(122);
|
||||
const hasDownImprovedVerticalStabilizer = useEquipment(124);
|
||||
|
||||
useEffect(() => {
|
||||
if (!yawInput.current) return;
|
||||
@@ -92,6 +93,7 @@ export function QuickInputs() {
|
||||
gunModelDefinition.pitch,
|
||||
turretModelDefinition.yaw,
|
||||
hasImprovedVerticalStabilizer,
|
||||
hasDownImprovedVerticalStabilizer,
|
||||
);
|
||||
modelTransformEvent.emit({ pitch, yaw });
|
||||
mutateDuel((state) => {
|
||||
@@ -133,6 +135,7 @@ export function QuickInputs() {
|
||||
gunModelDefinition.pitch,
|
||||
turretModelDefinition.yaw,
|
||||
hasImprovedVerticalStabilizer,
|
||||
hasDownImprovedVerticalStabilizer,
|
||||
);
|
||||
modelTransformEvent.emit({ pitch, yaw });
|
||||
mutateDuel((state) => {
|
||||
|
||||
+7
@@ -118,6 +118,11 @@ export function Controls({ naked }: ControlsProps) {
|
||||
duel.protagonist.tank.equipment_preset,
|
||||
duel.protagonist.equipmentMatrix,
|
||||
);
|
||||
const hasDownImprovedVerticalStabilizer = await hasEquipment(
|
||||
124,
|
||||
duel.protagonist.tank.equipment_preset,
|
||||
duel.protagonist.equipmentMatrix,
|
||||
);
|
||||
|
||||
switch (event) {
|
||||
case Pose.HullDown: {
|
||||
@@ -127,6 +132,7 @@ export function Controls({ naked }: ControlsProps) {
|
||||
protagonistGunModelDefinition.pitch,
|
||||
protagonistTurretModelDefinition.yaw,
|
||||
hasImprovedVerticalStabilizer,
|
||||
hasDownImprovedVerticalStabilizer,
|
||||
);
|
||||
|
||||
camera.position
|
||||
@@ -159,6 +165,7 @@ export function Controls({ naked }: ControlsProps) {
|
||||
protagonistGunModelDefinition.pitch,
|
||||
protagonistTurretModelDefinition.yaw,
|
||||
hasImprovedVerticalStabilizer,
|
||||
hasDownImprovedVerticalStabilizer,
|
||||
);
|
||||
|
||||
camera.position
|
||||
|
||||
+12
@@ -185,6 +185,11 @@ export function TankModel() {
|
||||
duel.protagonist.tank.equipment_preset,
|
||||
duel.protagonist.equipmentMatrix,
|
||||
);
|
||||
const hasDownImprovedVerticalStabilizer = await hasEquipment(
|
||||
124,
|
||||
duel.protagonist.tank.equipment_preset,
|
||||
duel.protagonist.equipmentMatrix,
|
||||
);
|
||||
const boundingRect = canvas.getBoundingClientRect();
|
||||
|
||||
delta.set(event.clientX, event.clientY).sub(position);
|
||||
@@ -196,6 +201,7 @@ export function TankModel() {
|
||||
gunModelDefinition.pitch,
|
||||
turretModelDefinition.yaw,
|
||||
hasImprovedVerticalStabilizer,
|
||||
hasDownImprovedVerticalStabilizer,
|
||||
);
|
||||
modelTransformEvent.emit({ pitch, yaw });
|
||||
}
|
||||
@@ -287,6 +293,11 @@ export function TankModel() {
|
||||
duel.protagonist.tank.equipment_preset,
|
||||
duel.protagonist.equipmentMatrix,
|
||||
);
|
||||
const hasDownImprovedVerticalStabilizer = await hasEquipment(
|
||||
124,
|
||||
duel.protagonist.tank.equipment_preset,
|
||||
duel.protagonist.equipmentMatrix,
|
||||
);
|
||||
const boundingRect = canvas.getBoundingClientRect();
|
||||
delta.set(event.clientX, event.clientY).sub(position);
|
||||
position.set(event.clientX, event.clientY);
|
||||
@@ -297,6 +308,7 @@ export function TankModel() {
|
||||
gunModelDefinition.pitch,
|
||||
turretModelDefinition.yaw,
|
||||
hasImprovedVerticalStabilizer,
|
||||
hasDownImprovedVerticalStabilizer,
|
||||
);
|
||||
modelTransformEvent.emit({ pitch, yaw });
|
||||
}
|
||||
|
||||
+2
@@ -41,6 +41,7 @@ export const TankSandbox = forwardRef<HTMLCanvasElement, TankSandboxProps>(
|
||||
const mutateTankopediaEphemeral = TankopediaEphemeral.useMutation();
|
||||
const canvas = useRef<HTMLCanvasElement>(null);
|
||||
const hasImprovedVerticalStabilizer = useEquipment(122);
|
||||
const hasDownImprovedVerticalStabilizer = useEquipment(124);
|
||||
const protagonistGun = Duel.use((state) => state.protagonist.gun);
|
||||
const protagonistTurret = Duel.use((state) => state.protagonist.turret);
|
||||
const mutateDuel = Duel.useMutation();
|
||||
@@ -82,6 +83,7 @@ export const TankSandbox = forwardRef<HTMLCanvasElement, TankSandboxProps>(
|
||||
gunModelDefinition.pitch,
|
||||
turretModelDefinition.yaw,
|
||||
hasImprovedVerticalStabilizer,
|
||||
hasDownImprovedVerticalStabilizer,
|
||||
);
|
||||
|
||||
modelTransformEvent.emit({ pitch, yaw });
|
||||
|
||||
@@ -12,6 +12,7 @@ export function applyPitchYawLimits(
|
||||
pitchLimits: PitchLimits, // deg
|
||||
yawLimits?: YawLimits, // deg
|
||||
verticalStabilizer = false,
|
||||
downVerticalStabilizer = false,
|
||||
) {
|
||||
let newPitch = pitch;
|
||||
let newYaw = yaw;
|
||||
@@ -22,7 +23,8 @@ export function applyPitchYawLimits(
|
||||
);
|
||||
}
|
||||
|
||||
const depressionBuff = verticalStabilizer ? degToRad(3) : 0;
|
||||
const depressionBuff =
|
||||
verticalStabilizer || downVerticalStabilizer ? degToRad(3) : 0;
|
||||
const elevationBuff = verticalStabilizer ? degToRad(4) : 0;
|
||||
let lowerPitch = -degToRad(pitchLimits.max) - depressionBuff;
|
||||
let upperPitch = -degToRad(pitchLimits.min) + elevationBuff;
|
||||
|
||||
@@ -109,6 +109,7 @@ export function tankCharacteristics(
|
||||
const hasEngineAccelerator = equipment(117);
|
||||
const hasCamouflageNet = equipment(115);
|
||||
const hasImprovedVerticalStabilizer = equipment(122);
|
||||
const hasDownImprovedVerticalStabilizer = equipment(124);
|
||||
const hasImprovedSuspension = equipment(123);
|
||||
|
||||
const hasTungsten = consumable(45);
|
||||
@@ -425,7 +426,8 @@ export function tankCharacteristics(
|
||||
const gunDepression =
|
||||
gunModelDefinition.pitch.max +
|
||||
gunDefaultPitch +
|
||||
(hasImprovedVerticalStabilizer ? 3 : 0);
|
||||
(hasImprovedVerticalStabilizer ? 3 : 0) +
|
||||
(hasDownImprovedVerticalStabilizer ? 3 : 0);
|
||||
const gunElevation =
|
||||
-gunModelDefinition.pitch.min -
|
||||
gunDefaultPitch +
|
||||
|
||||
@@ -7,6 +7,7 @@ import Navbar from '../components/Navbar.astro';
|
||||
import Party3 from '../components/Party3.astro';
|
||||
import './base.css';
|
||||
import { DEFAULT_LOCALE } from '@blitzkit/i18n';
|
||||
import Funny from '../components/Funny.astro';
|
||||
|
||||
export interface Props {
|
||||
noFooter?: boolean;
|
||||
@@ -23,6 +24,10 @@ const locale = Astro.params.locale ?? DEFAULT_LOCALE;
|
||||
<link rel="icon" type="image/x-icon" href="/favicon.png" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<link rel="sitemap" href="/sitemap-index.xml" />
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=Schoolbell&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
|
||||
<Party3 />
|
||||
|
||||
@@ -39,7 +44,11 @@ const locale = Astro.params.locale ?? DEFAULT_LOCALE;
|
||||
window.location.pathname.startsWith(`/${locale}`),
|
||||
);
|
||||
|
||||
if (!isAPI && bestLocale !== currentPathLocale) {
|
||||
if (
|
||||
!isAPI && // not an api, duh!
|
||||
localStorage.getItem('preferred-locale') !== null && // no preference, so probably google's crawler
|
||||
bestLocale !== currentPathLocale // we need to redirect
|
||||
) {
|
||||
window.location.pathname = isI18nPath
|
||||
? window.location.pathname.replace(
|
||||
`/${currentPathLocale}`,
|
||||
@@ -51,6 +60,8 @@ const locale = Astro.params.locale ?? DEFAULT_LOCALE;
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<Funny />
|
||||
|
||||
<BlitzKitTheme>
|
||||
<Flex direction="column" minHeight="100vh">
|
||||
<Navbar />
|
||||
|
||||
@@ -2,4 +2,48 @@
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
cursor:
|
||||
url(https://i.imgur.com/MeQQWCX.png) 16 16,
|
||||
auto;
|
||||
}
|
||||
|
||||
* {
|
||||
font-family: 'Schoolbell', cursive !important;
|
||||
}
|
||||
|
||||
.radix-themes {
|
||||
--gray-1: var(--crimson-5);
|
||||
--gray-2: var(--crimson-5);
|
||||
--gray-3: var(--crimson-5);
|
||||
--gray-4: var(--crimson-6);
|
||||
--gray-5: var(--crimson-6);
|
||||
--gray-6: var(--crimson-7);
|
||||
--gray-7: var(--crimson-7);
|
||||
--gray-8: var(--crimson-8);
|
||||
--gray-9: var(--crimson-9);
|
||||
--gray-10: var(--crimson-10);
|
||||
--gray-11: var(--crimson-11);
|
||||
--gray-12: var(--crimson-12);
|
||||
}
|
||||
|
||||
.star {
|
||||
position: fixed;
|
||||
color: yellow;
|
||||
font-size: 20px;
|
||||
pointer-events: none;
|
||||
animation:
|
||||
fade-out 0.6s ease-out forwards,
|
||||
move-up 0.6s ease-out forwards;
|
||||
}
|
||||
|
||||
@keyframes fade-out {
|
||||
to {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes move-up {
|
||||
to {
|
||||
transform: translateY(20px);
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,8 @@
|
||||
---
|
||||
import { assertSecret } from '@blitzkit/core';
|
||||
import { DEFAULT_LOCALE, SUPPORTED_LOCALES } from '@blitzkit/i18n';
|
||||
import { Box, Flex, Heading, Link } from '@radix-ui/themes';
|
||||
import { literals } from '@blitzkit/i18n/src/literals';
|
||||
import { Box, Flex, Heading, Link, Quote } from '@radix-ui/themes';
|
||||
import type { GetStaticPaths } from 'astro';
|
||||
import { AesonPlug } from '../../components/AesonPlug';
|
||||
import { HomeLocaleSwitcher } from '../../components/Home/HomeLocaleSwitcher';
|
||||
@@ -21,7 +22,6 @@ import {
|
||||
tierListTool,
|
||||
} from '../../constants/tools';
|
||||
import { getStrings } from '../../core/i18n/getStrings';
|
||||
import { literals } from '@blitzkit/i18n/src/literals';
|
||||
import BaseLayout from '../../layouts/BaseLayout.astro';
|
||||
|
||||
const PUBLIC_ASSET_BRANCH = assertSecret(import.meta.env.PUBLIC_ASSET_BRANCH);
|
||||
@@ -45,6 +45,20 @@ export const getStaticPaths = (() => {
|
||||
<BaseLayout>
|
||||
<HomeHero />
|
||||
|
||||
<Flex justify="center" pt="6" px="8">
|
||||
<Flex flexGrow="1" maxWidth="32rem" justify="center">
|
||||
<Quote
|
||||
className="no-funny"
|
||||
style={{
|
||||
fontSize: '1.3em',
|
||||
}}
|
||||
>
|
||||
It has come to our attention that tanks are very harsh objects. To even
|
||||
it out, we made the website a pretty pretty princess {'<'}3
|
||||
</Quote>
|
||||
</Flex>
|
||||
</Flex>
|
||||
|
||||
<HomeLocaleSwitcher {locale} client:load />
|
||||
|
||||
{
|
||||
|
||||
+3
-16
@@ -9,28 +9,15 @@ datasource db {
|
||||
}
|
||||
|
||||
model User {
|
||||
blitz_id Int @id @map("blitz") // map: "blitz" was too vague
|
||||
last_used DateTime? @default(now())
|
||||
tank_votes TankVote[]
|
||||
blitz_id BigInt @id @map("blitz") // map: "blitz" was too vague
|
||||
last_used DateTime? @default(now())
|
||||
|
||||
@@map("Users") // map: "Users" was mistakenly plural
|
||||
}
|
||||
|
||||
model TankVote {
|
||||
id Int @id
|
||||
last_updated DateTime @default(now())
|
||||
easiness Int?
|
||||
firepower Int?
|
||||
maneuverability Int?
|
||||
survivability Int?
|
||||
|
||||
user User @relation(fields: [user_blitz_id], references: [blitz_id])
|
||||
user_blitz_id Int
|
||||
}
|
||||
|
||||
model DiscordUser {
|
||||
discord_id BigInt @id @map("discord") // map: "discord" was too vague
|
||||
blitz_id Int @map("blitz") // map: "blitz" was too vague
|
||||
blitz_id BigInt @map("blitz") // map: "blitz" was too vague
|
||||
|
||||
@@map("DiscordUsers") // map: "DiscordUsers" was mistakenly plural
|
||||
}
|
||||
Submodule
+1
Submodule submodules/CUE4Parse added at 624e07c8c3.
Submodule submodules/blitzkit-closed updated: c1d631764f...31937a9f1e.
Reference in new issue
Block a user