Compare commits

...
21 Commits
Author SHA1 Message Date
TrèsAbhi c54ceb944e Merge pull request #94 from tresabhi/1.16.3 2024-03-12 22:43:51 -05:00
TrèsAbhi 37a2ba3566 feat: docs 2024-03-12 18:07:32 -05:00
TrèsAbhi caff7bb6d0 feat: improved vertical stablizer model compat 2024-03-12 18:00:00 -05:00
TrèsAbhi 01c491aee0 feat: 1 more decimal in pitch and yaw 2024-03-12 17:40:58 -05:00
TrèsAbhi fd408d6777 fix: use initial gun pitches correctly 2024-03-12 17:39:46 -05:00
TrèsAbhi 6d1ed1e56e fix: reveals a few hidden values 2024-03-12 17:09:21 -05:00
TrèsAbhi 46f9d605f7 fix: intra clip spelling 2024-03-12 16:53:42 -05:00
TrèsAbhi a65ea42b81 Update cd-ratings-na.yml 2024-03-12 13:22:03 -05:00
TrèsAbhi 40f8c6a915 Update cd-ratings-eu.yml 2024-03-12 13:21:19 -05:00
TrèsAbhi 4678359f36 Update cd-ratings-asia.yml 2024-03-12 13:20:58 -05:00
TrèsAbhi f91bd63646 whooped 2024-03-10 12:50:25 -05:00
TrèsAbhi c1872262f5 huh 2024-03-10 12:29:04 -05:00
TrèsAbhi 082e112758 Update constants.ts 2024-03-10 10:54:27 -05:00
TrèsAbhi 4cb7d50eb5 Update cd-assets.yml 2024-03-10 10:53:34 -05:00
TrèsAbhi 8c050add23 my butt 2024-03-09 23:33:14 -06:00
TrèsAbhi 2610697d86 wee ooo wee oo 2024-03-09 23:04:09 -06:00
TrèsAbhi 64f1de37ad help me 2024-03-09 22:50:55 -06:00
TrèsAbhi 58f6862279 aaaaaaaaaaaaaaaaaaaaaa 2024-03-09 22:46:21 -06:00
TrèsAbhi b47f6fdb32 i dunno xd 2024-03-09 22:42:03 -06:00
TrèsAbhi ce5a53d0ff i dunno 2024-03-09 22:39:04 -06:00
TrèsAbhi 6ee1fa13d3 fix: use require 2024-03-09 22:15:22 -06:00
27 changed files with 217 additions and 119 deletions

No files matched your search

+5 -4
View File
@@ -2,10 +2,10 @@ name: CD Build Assets
on:
push:
branches: dev
branches: [dev, main]
workflow_dispatch:
# schedule:
# - cron: '0 0 * * *'
schedule:
- cron: '0 0 * * *'
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
@@ -44,10 +44,11 @@ jobs:
run: yarn setup:depotdownloader
- name: Run DepotDownloader
run: ./temp/depotDownloader/DepotDownloader.exe -app 444202 -username ${{ secrets.DEPOT_DOWNLOADER_USERNAME }} -password "${{ secrets.DEPOT_DOWNLOADER_PASSWORD }}"
run: ./temp/depotDownloader/DepotDownloader.exe -app 444200 -username ${{ secrets.DEPOT_DOWNLOADER_USERNAME }} -password "${{ secrets.DEPOT_DOWNLOADER_PASSWORD }}"
- name: Build assets
run: |
$env:GH_TOKEN = "${{ secrets.GH_TOKEN }}"
$env:DISCORD_TOKEN = "${{ secrets.DISCORD_TOKEN }}"
$env:DISCORD_BLITZ_DB = "${{ secrets.DISCORD_BLITZ_DB }}"
yarn build:assets --all-targets --depot ${{ github.ref == 'refs/heads/main' && '--production' || '' }}
+1 -1
View File
@@ -35,4 +35,4 @@ jobs:
run: yarn
- name: Generate leaderboard
run: GH_TOKEN=${{ secrets.GH_TOKEN }} DISCORD_TOKEN=${{ secrets.DISCORD_TOKEN }} yarn publish:ratingsleaderboard --region=asia --target=${{ github.event.schedule == '0 0 * * *' && 'latest' || 'midnight' }}
run: GH_TOKEN=${{ secrets.GH_TOKEN }} DISCORD_TOKEN=${{ secrets.DISCORD_TOKEN }} DISCORD_BLITZ_DB=${{ secrets.DISCORD_BLITZ_DB }} yarn publish:ratingsleaderboard --region=asia --target=${{ github.event.schedule == '0 0 * * *' && 'latest' || 'midnight' }}
+1 -1
View File
@@ -35,4 +35,4 @@ jobs:
run: yarn
- name: Generate leaderboard
run: GH_TOKEN=${{ secrets.GH_TOKEN }} DISCORD_TOKEN=${{ secrets.DISCORD_TOKEN }} yarn publish:ratingsleaderboard --region=eu --target=${{ github.event.schedule == '0 0 * * *' && 'latest' || 'midnight' }}
run: GH_TOKEN=${{ secrets.GH_TOKEN }} DISCORD_TOKEN=${{ secrets.DISCORD_TOKEN }} DISCORD_BLITZ_DB=${{ secrets.DISCORD_BLITZ_DB }} yarn publish:ratingsleaderboard --region=eu --target=${{ github.event.schedule == '0 0 * * *' && 'latest' || 'midnight' }}
+1 -1
View File
@@ -35,4 +35,4 @@ jobs:
run: yarn
- name: Generate leaderboard
run: GH_TOKEN=${{ secrets.GH_TOKEN }} DISCORD_TOKEN=${{ secrets.DISCORD_TOKEN }} yarn publish:ratingsleaderboard --region=na --target=${{ github.event.schedule == '0 0 * * *' && 'latest' || 'midnight' }}
run: GH_TOKEN=${{ secrets.GH_TOKEN }} DISCORD_TOKEN=${{ secrets.DISCORD_TOKEN }} DISCORD_BLITZ_DB=${{ secrets.DISCORD_BLITZ_DB }} yarn publish:ratingsleaderboard --region=na --target=${{ github.event.schedule == '0 0 * * *' && 'latest' || 'midnight' }}
+1
View File
@@ -73,6 +73,7 @@
"lods",
"metallicness",
"minitelrose",
"Minotauro",
"MIPMAPCOUNT",
"modeltransform",
"MURICA",
+36
View File
@@ -0,0 +1,36 @@
# Blitzkrieg 1.16.2
¡Hola desde el mundo del español!
## Features
- Added translations for Spanish to the bot
- Your language will be inferred automatically from your Discord settings
- Any untranslated languages and words we forgot to translate will be left in English
- If you have your language set to Spanish and see English in any places, please let us know on [the official Discord server](https://discord.gg/nDt7AjGJQH)
- All `/about` commands except for `commands` remain in English
- Tank names are still in English
- The website remains unchanged
- The title bar (featured as the big text on top of most commands) has now been made more compact
## Changes
- "Tank type" is now called "tank class"
- Removed `/player-achievements` and `search-tanks`
- They will be reintroduced in the future in a far better way
- Also removed a `SKLLD` server exclusive `/eligible` command
- This will be generalized for all clans in the future
## Fixes
- Fixed the red glowing floor underneath the tank sandbox
- This has been replaced with a static image
- The refresh button is now properly removed when lacking permissions
- Tank names that start with a number are now properly inferred from command inputs
## Technical Changes
- Command registration is now error tolerant meaning that if a single command fails to initiate, it will be discarded until the next restart
- We are currently looking into how we can allow the command to retry registration after a fixed amount of time
- Due to the implications of the code added which can be very easily exploited by hackers, a single file has been added to the repository as a closed source submodule and will remain closed unless a third party open-source implementation is made public
- Removed preview commands
+21
View File
@@ -0,0 +1,21 @@
# Blitzkrieg 1.16.3
Further polishing and corrections for the Tankopedia.
## Features
- Added a few more stats to view for the Tankopedia
- Added the count of shells in the magazine for auto-reloaders
- The optimal shell index was moved below this stats
- Shell reloads for auto-reloaders now abide crew stats
- Intra-clip is now also shown for auto-reloaders
- Added 1 more decimal place worth of precision when viewing and changing gun pitch and yaw
## Fixes
- "Inter-clip" is now correctly spelled as "intra-clip"
- Tanks with initial gun pitches (like the Minotauro) are now handled correctly
- The stats now reflect the fact that the gun is naturally pitched downwards
- The view model now compensates for the natural pitch
- Tanks with the improved vertical stabilizer equipment are now handled correctly
- The view model now allows you to pitch the gun further as intended when the equipment is on
+5 -5
View File
@@ -1,13 +1,13 @@
import { readdir } from 'fs/promises';
import { argv } from 'process';
const isDepot = argv.includes('--depot');
export const WOTB_WIN32_DEPOT = 444202;
export const DATA = isDepot
? // ? await (async () => {
// const [installationVersion] = await readdir(`depots/${WOTB_WIN32_DEPOT}`);
// return `depots/${WOTB_WIN32_DEPOT}/${installationVersion}/Data`;
// })()
`depots/${WOTB_WIN32_DEPOT}/Data`
? await (async () => {
const [installationVersion] = await readdir(`depots/${WOTB_WIN32_DEPOT}`);
return `depots/${WOTB_WIN32_DEPOT}/${installationVersion}/Data`;
})()
: 'C:/Program Files (x86)/Steam/steamapps/common/World of Tanks Blitz/Data';
export const POI = {
+2 -2
View File
@@ -674,7 +674,7 @@ export async function definitions(production: boolean) {
: turretGunEntry.reloadTime;
const gunClipCount =
gunType === 'regular' ? undefined : turretGunEntry.clip!.count;
const gunInterClip =
const gunIntraClip =
gunType === 'regular'
? undefined
: 60 / turretGunEntry.clip!.rate;
@@ -722,7 +722,7 @@ export async function definitions(production: boolean) {
type: gunType,
reload: gunReload,
count: gunClipCount,
interClip: gunInterClip,
intraClip: gunIntraClip,
camouflageLoss:
typeof turretGunEntry.invisibilityFactorAtShot === 'number'
? turretGunEntry.invisibilityFactorAtShot
@@ -4,6 +4,7 @@ import { debounce } from 'lodash';
import { use, useEffect, useRef, useState } from 'react';
import { lerp } from 'three/src/math/MathUtils';
import { ShellButton } from '../../../../../../components/ModuleButtons/ShellButton';
import { applyPitchYawLimits } from '../../../../../../core/blitz/applyPitchYawLimits';
import { isExplosive } from '../../../../../../core/blitz/isExplosive';
import { resolveNearPenetration } from '../../../../../../core/blitz/resolveNearPenetration';
import { coefficient } from '../../../../../../core/blitzkrieg/coefficient';
@@ -56,6 +57,7 @@ export function Characteristics() {
turretModelDefinition.boundingBox,
),
);
const gunDefaultPitch = tankModelDefinition.turretRotation?.pitch ?? 0;
const weight =
tank.weight + engine.weight + track.weight + turret.weight + gun.weight;
const weightTons = weight / 1000;
@@ -113,7 +115,7 @@ export function Characteristics() {
// TODO: add max rolls
[hasTungsten, 0.15],
);
const interClipCoefficient = coefficient([hasShellReloadBoost, -0.3]);
const intraClipCoefficient = coefficient([hasShellReloadBoost, -0.3]);
const shellVelocityCoefficient = coefficient(
[hasSupercharger, 0.3],
[hasImprovedGunPowder, 0.3],
@@ -210,7 +212,7 @@ export function Characteristics() {
shell,
damageCoefficient,
reloadCoefficient,
interClipCoefficient,
intraClipCoefficient,
);
useEffect(() => {
@@ -218,6 +220,17 @@ export function Characteristics() {
penetrationDistanceInput.current.value = `${penetrationDistance}`;
}
}, [penetrationDistance]);
useEffect(() => {
mutateDuel((draft) => {
[draft.protagonist!.pitch, draft.protagonist!.yaw] = applyPitchYawLimits(
draft.protagonist!.pitch,
draft.protagonist!.yaw,
gunModelDefinition.pitch,
turretModelDefinition.yaw,
hasImprovedVerticalStabilizer,
);
});
}, [hasImprovedVerticalStabilizer]);
return (
<Flex direction="column" gap="8" style={{ width: '100%' }}>
@@ -255,7 +268,7 @@ export function Characteristics() {
<>
<InfoWithDelta decimals={0} indent name="Maximum" unit="hp / min">
{gun.reload.at(-1)! < gun.reload.at(-2)!
? (shell.damage.armor / (gun.reload.at(-1)! + gun.interClip)) *
? (shell.damage.armor / (gun.reload.at(-1)! + gun.intraClip)) *
60
: (shell.damage.armor / gun.reload[0]) * 60}
</InfoWithDelta>
@@ -266,12 +279,12 @@ export function Characteristics() {
unit="hp / min"
>
{gun.reload.at(-1)! < gun.reload.at(-2)!
? (shell.damage.armor / (gun.reload.at(-1)! + gun.interClip)) *
? (shell.damage.armor / (gun.reload.at(-1)! + gun.intraClip)) *
(60 -
(gun.reload.slice(0, -1).length - 1) * gun.interClip) +
(gun.reload.slice(0, -1).length - 1) * gun.intraClip) +
shell.damage.armor * gun.reload.slice(0, -1).length
: (shell.damage.armor / (gun.reload[0] + gun.interClip)) *
(60 - (gun.reload.slice(1).length - 1) * gun.interClip) +
: (shell.damage.armor / (gun.reload[0] + gun.intraClip)) *
(60 - (gun.reload.slice(1).length - 1) * gun.intraClip) +
shell.damage.armor * gun.reload.slice(1).length}
</InfoWithDelta>
<Info
@@ -285,14 +298,15 @@ export function Characteristics() {
</a>
}
/>
<Info indent name="Optimal shell index">
{gun.reload.at(-1)! < gun.reload.at(-2)! ? gun.reload.length : 1}
</Info>
</>
)}
{gun.type === 'autoReloader' ? (
<>
<Info name="Reload" unit="s" />
<InfoWithDelta name="Shells">{gun.reload.length}</InfoWithDelta>
<Info indent name="Most optimal">
{gun.reload.at(-1)! < gun.reload.at(-2)! ? gun.reload.length : 1}
</Info>
<Info name="Shell reloads" unit="s" />
{gun.reload.map((reload, index) => (
<InfoWithDelta
key={index}
@@ -301,7 +315,7 @@ export function Characteristics() {
decimals={2}
deltaType="lowerIsBetter"
>
{reload}
{reload * reloadCoefficient}
</InfoWithDelta>
))}
</>
@@ -315,17 +329,18 @@ export function Characteristics() {
{gun.reload * reloadCoefficient}
</InfoWithDelta>
)}
{gun.type === 'autoLoader' && (
<InfoWithDelta
indent
decimals={2}
name="Inter-clip reload"
unit="s"
deltaType="lowerIsBetter"
>
{gun.interClip * interClipCoefficient}
</InfoWithDelta>
)}
{gun.type === 'autoLoader' ||
(gun.type === 'autoReloader' && (
<InfoWithDelta
indent
decimals={2}
name="Intra-clip"
unit="s"
deltaType="lowerIsBetter"
>
{gun.intraClip * intraClipCoefficient}
</InfoWithDelta>
))}
<InfoWithDelta name="Caliber" decimals={0} unit="mm">
{shell.caliber}
</InfoWithDelta>
@@ -457,10 +472,12 @@ export function Characteristics() {
<Info name="Gun flexibility" unit="°" />
<InfoWithDelta decimals={1} indent name="Depression">
{gunModelDefinition.pitch.max +
gunDefaultPitch +
(hasImprovedVerticalStabilizer ? 3 : 0)}
</InfoWithDelta>
<InfoWithDelta decimals={1} indent name="Elevation">
{-gunModelDefinition.pitch.min +
{-gunModelDefinition.pitch.min -
gunDefaultPitch +
(hasImprovedVerticalStabilizer ? 3 : 0)}
</InfoWithDelta>
{gunModelDefinition.pitch.front && (
@@ -4,6 +4,7 @@ import { useEffect, useRef } from 'react';
import { Vector3 } from 'three';
import { OrbitControls as OrbitControlsClass } from 'three-stdlib';
import { applyPitchYawLimits } from '../../../../../core/blitz/applyPitchYawLimits';
import { hasEquipment } from '../../../../../core/blitzkrieg/hasEquipment';
import { modelDefinitions } from '../../../../../core/blitzkrieg/modelDefinitions';
import { Pose, poseEvent } from '../../../../../core/blitzkrieg/pose';
import { useAwait } from '../../../../../hooks/useAwait';
@@ -67,7 +68,9 @@ export function Controls() {
},
);
function handlePoseEvent(event: Pose) {
async function handlePoseEvent(event: Pose) {
const hasImprovedVerticalStabilizer = await hasEquipment(122);
switch (event) {
case Pose.HullDown: {
const [pitch] = applyPitchYawLimits(
@@ -75,6 +78,7 @@ export function Controls() {
0,
protagonistGunModelDefinition.pitch,
protagonistTurretModelDefinition.yaw,
hasImprovedVerticalStabilizer,
);
camera.position
@@ -106,6 +110,7 @@ export function Controls() {
0,
protagonistGunModelDefinition.pitch,
protagonistTurretModelDefinition.yaw,
hasImprovedVerticalStabilizer,
);
camera.position
@@ -11,6 +11,7 @@ import { modelDefinitions } from '../../../../../../core/blitzkrieg/modelDefinit
import { modelTransformEvent } from '../../../../../../core/blitzkrieg/modelTransform';
import { Pose, poseEvent } from '../../../../../../core/blitzkrieg/pose';
import { tankIcon } from '../../../../../../core/blitzkrieg/tankIcon';
import { useEquipment } from '../../../../../../hooks/useEquipment';
import { useWideFormat } from '../../../../../../hooks/useWideFormat';
import { mutateDuel, useDuel } from '../../../../../../stores/duel';
import mutateTankopediaPersistent, {
@@ -29,6 +30,7 @@ import { TankModel } from './components/TankModel';
export function TankSandbox() {
const canvas = useRef<HTMLCanvasElement>(null);
const hasImprovedVerticalStabilizer = useEquipment(122);
const awaitedModelDefinitions = use(modelDefinitions);
const canvasWrapper = useRef<HTMLDivElement>(null);
const [isFullScreen, setIsFullScreen] = useState(false);
@@ -70,6 +72,7 @@ export function TankSandbox() {
0,
gunModelDefinition.pitch,
turretModelDefinition.yaw,
hasImprovedVerticalStabilizer,
);
modelTransformEvent.emit({ pitch, yaw });
@@ -87,6 +90,7 @@ export function TankSandbox() {
0,
gunModelDefinition.pitch,
turretModelDefinition.yaw,
hasImprovedVerticalStabilizer,
);
modelTransformEvent.emit({ pitch, yaw });
@@ -104,6 +108,7 @@ export function TankSandbox() {
0,
gunModelDefinition.pitch,
turretModelDefinition.yaw,
hasImprovedVerticalStabilizer,
);
modelTransformEvent.emit({ pitch, yaw });
@@ -131,6 +136,7 @@ export function TankSandbox() {
draft.protagonist!.yaw,
gunModelDefinition.pitch,
turretModelDefinition.yaw,
hasImprovedVerticalStabilizer,
);
});
}, [protagonist.gun, protagonist.turret]);
@@ -4,6 +4,7 @@ import { Euler, Group, Vector3 } from 'three';
import { degToRad } from 'three/src/math/MathUtils';
import { I_HAT, J_HAT, K_HAT } from '../../../../../../../constants/axis';
import { applyPitchYawLimits } from '../../../../../../../core/blitz/applyPitchYawLimits';
import { hasEquipment } from '../../../../../../../core/blitzkrieg/hasEquipment';
import { jsxTree } from '../../../../../../../core/blitzkrieg/jsxTree';
import { modelDefinitions } from '../../../../../../../core/blitzkrieg/modelDefinitions';
import {
@@ -106,7 +107,6 @@ export const TankModel = memo(() => {
const turretModelDefinition =
tankModelDefinition.turrets[protagonist.turret.id];
const gunModelDefinition = turretModelDefinition.guns[protagonist.gun.id];
const { gltf } = useModel(protagonist.tank.id);
const nodes = Object.values(gltf.nodes);
@@ -161,12 +161,14 @@ export const TankModel = memo(() => {
window.addEventListener('pointerup', handlePointerUp);
}
}
function handlePointerMove(event: PointerEvent) {
async function handlePointerMove(event: PointerEvent) {
const hasImprovedVerticalStabilizer = await hasEquipment(122);
[pitch, yaw] = applyPitchYawLimits(
pitch,
yaw + event.movementX * (Math.PI / canvas.width),
gunModelDefinition.pitch,
turretModelDefinition.yaw,
hasImprovedVerticalStabilizer,
);
modelTransformEvent.emit({ pitch, yaw });
}
@@ -220,12 +222,14 @@ export const TankModel = memo(() => {
window.addEventListener('pointermove', handlePointerMove);
window.addEventListener('pointerup', handlePointerUp);
}
function handlePointerMove(event: PointerEvent) {
async function handlePointerMove(event: PointerEvent) {
const hasImprovedVerticalStabilizer = await hasEquipment(122);
[pitch, yaw] = applyPitchYawLimits(
pitch - event.movementY * (Math.PI / canvas.height),
yaw + event.movementX * (Math.PI / canvas.width),
gunModelDefinition.pitch,
turretModelDefinition.yaw,
hasImprovedVerticalStabilizer,
);
modelTransformEvent.emit({ pitch, yaw });
}
@@ -1,5 +1,6 @@
import { Flex, TextField } from '@radix-ui/themes';
import { use, useEffect, useRef } from 'react';
import { degToRad, radToDeg } from 'three/src/math/MathUtils';
import { applyPitchYawLimits } from '../../../../../../core/blitz/applyPitchYawLimits';
import { modelDefinitions } from '../../../../../../core/blitzkrieg/modelDefinitions';
import { modelTransformEvent } from '../../../../../../core/blitzkrieg/modelTransform';
@@ -20,22 +21,21 @@ export function RotationInputs({ isFullScreen }: RotationInputsProps) {
const mode = useTankopediaPersistent((state) => state.mode);
const hasCalibratedShells = useEquipment(103, true);
const hasEnhancedArmor = useEquipment(110);
useEffect(() => {
turretYawInput.current!.value = `${-Math.round(
protagonist.yaw * (180 / Math.PI),
)}`;
}, [protagonist.yaw]);
useEffect(() => {
gunPitchInput.current!.value = `${-Math.round(
protagonist.pitch * (180 / Math.PI),
)}`;
}, [protagonist.pitch]);
const tankModelDefinition = awaitedModelDefinitions[protagonist.tank.id];
const turretModelDefinition =
tankModelDefinition.turrets[protagonist.turret.id];
const gunModelDefinition = turretModelDefinition.guns[protagonist.gun.id];
const initialGunPitch = tankModelDefinition.turretRotation?.pitch ?? 0;
const hasImprovedVerticalStabilizer = useEquipment(122);
useEffect(() => {
turretYawInput.current!.value = radToDeg(protagonist.yaw).toFixed(1);
}, [protagonist.yaw]);
useEffect(() => {
gunPitchInput.current!.value = (
-radToDeg(protagonist.pitch) + initialGunPitch
).toFixed(1);
}, [protagonist.pitch]);
return (
<Flex
@@ -68,22 +68,22 @@ export function RotationInputs({ isFullScreen }: RotationInputsProps) {
Yaw
</TextField.Slot>
<TextField.Input
defaultValue={Math.round(protagonist.yaw * (180 / Math.PI))}
onBlur={() => {
const [pitch, yaw] = applyPitchYawLimits(
protagonist.pitch,
-Number(turretYawInput.current?.value) * (Math.PI / 180),
degToRad(Number(turretYawInput.current!.value)),
gunModelDefinition.pitch,
turretModelDefinition.yaw,
hasImprovedVerticalStabilizer,
);
modelTransformEvent.emit({ pitch, yaw });
mutateDuel((state) => {
state.protagonist!.pitch = pitch;
state.protagonist!.yaw = yaw;
});
turretYawInput.current!.value = `${Math.round(
yaw * (180 / Math.PI),
)}`;
turretYawInput.current!.value = radToDeg(protagonist.yaw).toFixed(
1,
);
}}
onKeyDown={(event) => {
if (event.key === 'Enter') {
@@ -116,22 +116,24 @@ export function RotationInputs({ isFullScreen }: RotationInputsProps) {
Pitch
</TextField.Slot>
<TextField.Input
defaultValue={-Math.round(protagonist.pitch * (180 / Math.PI))}
onBlur={() => {
const [pitch, yaw] = applyPitchYawLimits(
-Number(gunPitchInput.current?.value) * (Math.PI / 180),
degToRad(
-Number(gunPitchInput.current!.value) + initialGunPitch,
),
protagonist.yaw,
gunModelDefinition.pitch,
turretModelDefinition.yaw,
hasImprovedVerticalStabilizer,
);
modelTransformEvent.emit({ pitch, yaw });
mutateDuel((state) => {
state.protagonist!.pitch = pitch;
state.protagonist!.yaw = yaw;
});
gunPitchInput.current!.value = `${Math.round(
pitch * (180 / Math.PI),
)}`;
gunPitchInput.current!.value = (
-radToDeg(protagonist.pitch) + initialGunPitch
).toFixed(1);
}}
onKeyDown={(event) => {
if (event.key === 'Enter') {
@@ -34,7 +34,7 @@ export function WN8SurroundingStat({
style={{
color: theme.colors.textHighContrast,
fontSize: 24,
fontWeight: 'bold',
fontWeight: 700,
}}
>
{value}
@@ -63,7 +63,7 @@ export function RowStat({
<span
style={{
color: theme.textHighContrast,
fontWeight: 'bold',
fontWeight: 700,
fontSize: 16,
textAlign: 'center',
}}
@@ -30,7 +30,7 @@ export default function GenericStatsRow({ stat }: GenericStatsRowProps) {
<span
style={{
color: theme.colors.textHighContrast,
fontWeight: 'bold',
fontWeight: 700,
fontSize: 16,
display: 'flex',
alignItems: 'center',
+17 -18
View File
@@ -1,4 +1,5 @@
import { clamp } from 'lodash';
import { degToRad } from 'three/src/math/MathUtils';
import { PitchLimits, YawLimits } from '../blitzkrieg/modelDefinitions';
import { normalizeAngleRad } from '../math/normalizeAngleRad';
@@ -7,33 +8,31 @@ export function applyPitchYawLimits(
yaw: number, // rad
pitchLimits: PitchLimits, // deg
yawLimits?: YawLimits, // deg
verticalStabilizer = false,
) {
let newPitch = pitch;
let newYaw = yaw;
if (yawLimits) {
newYaw = normalizeAngleRad(
clamp(
newYaw,
-yawLimits.max * (Math.PI / 180),
-yawLimits.min * (Math.PI / 180),
),
clamp(newYaw, -degToRad(yawLimits.max), -degToRad(yawLimits.min)),
);
}
let lowerPitch = -pitchLimits.max * (Math.PI / 180);
let upperPitch = -pitchLimits.min * (Math.PI / 180);
const transition = (pitchLimits.transition ?? 10) * (Math.PI / 180);
const pitchBuff = verticalStabilizer ? degToRad(3) : 0;
let lowerPitch = -degToRad(pitchLimits.max) - pitchBuff;
let upperPitch = -degToRad(pitchLimits.min) + pitchBuff;
const transition = degToRad(pitchLimits.transition ?? 10);
if (pitchLimits.back) {
const range = pitchLimits.back.range * (Math.PI / 180);
const range = degToRad(pitchLimits.back.range);
const yawRotatedAbs = Math.abs(normalizeAngleRad(newYaw - Math.PI));
if (yawRotatedAbs <= range + transition) {
if (yawRotatedAbs <= range) {
// inside range
lowerPitch = -pitchLimits.back.max * (Math.PI / 180);
upperPitch = -pitchLimits.back.min * (Math.PI / 180);
lowerPitch = -degToRad(pitchLimits.back.max);
upperPitch = -degToRad(pitchLimits.back.min);
} else {
// inside transition
const transitionProgress = (yawRotatedAbs - range) / transition;
@@ -44,21 +43,21 @@ export function applyPitchYawLimits(
(1 - transitionProgress) * pitchLimits.back.min +
transitionProgress * pitchLimits.min;
lowerPitch = -maxInterpolatedPitch * (Math.PI / 180);
upperPitch = -minInterpolatedPitch * (Math.PI / 180);
lowerPitch = -degToRad(maxInterpolatedPitch);
upperPitch = -degToRad(minInterpolatedPitch);
}
}
}
if (pitchLimits.front) {
const range = pitchLimits.front.range * (Math.PI / 180);
const range = degToRad(pitchLimits.front.range);
const yawAbs = Math.abs(normalizeAngleRad(newYaw));
if (yawAbs <= range + transition) {
if (yawAbs <= range) {
// inside range
lowerPitch = -pitchLimits.front.max * (Math.PI / 180);
upperPitch = -pitchLimits.front.min * (Math.PI / 180);
lowerPitch = -degToRad(pitchLimits.front.max);
upperPitch = -degToRad(pitchLimits.front.min);
} else {
// inside transition
const transitionProgress = (yawAbs - range) / transition;
@@ -69,8 +68,8 @@ export function applyPitchYawLimits(
(1 - transitionProgress) * pitchLimits.front.min +
transitionProgress * pitchLimits.min;
lowerPitch = -maxInterpolatedPitch * (Math.PI / 180);
upperPitch = -minInterpolatedPitch * (Math.PI / 180);
lowerPitch = -degToRad(maxInterpolatedPitch);
upperPitch = -degToRad(minInterpolatedPitch);
}
}
}
+5 -1
View File
@@ -1,9 +1,11 @@
import { degToRad } from 'three/src/math/MathUtils';
import {
DuelMember,
genericDefaultEquipmentMatrix,
mutateDuel,
} from '../../stores/duel';
import { availableProvisions } from './availableProvisions';
import { modelDefinitions } from './modelDefinitions';
import { provisionDefinitions } from './provisionDefinitions';
import { tankDefinitions } from './tankDefinitions';
@@ -13,6 +15,8 @@ export async function assignDuelMember(
) {
const awaitedTankDefinitions = await tankDefinitions;
const awaitedProvisionDefinitions = await provisionDefinitions;
const awaitedModelDefinitions = await modelDefinitions;
const tankModelDefinition = awaitedModelDefinitions[id];
const tank = awaitedTankDefinitions[id];
const turret = tank.turrets.at(-1)!;
const gun = turret.guns.at(-1)!;
@@ -32,7 +36,7 @@ export async function assignDuelMember(
shell,
track,
equipment: genericDefaultEquipmentMatrix,
pitch: 0,
pitch: degToRad(tankModelDefinition.turretRotation?.pitch ?? 0),
yaw: 0,
camouflage: true,
consumables: [],
-26
View File
@@ -1,26 +0,0 @@
import { readFile } from 'fs/promises';
import satori from 'satori';
const FONT_NAME = 'Roboto';
const FONT_FILES = [
{ weight: 400 as const, path: 'src/assets/fonts/Roboto.ttf' },
{ weight: 700 as const, path: 'src/assets/fonts/Roboto-Bold.ttf' },
{ weight: 900 as const, path: 'src/assets/fonts/Roboto-Black.ttf' },
];
const fonts = Promise.all(
FONT_FILES.map(({ path, weight }) =>
readFile(path).then((data) => ({
data: Buffer.from(data.buffer),
name: FONT_NAME,
weight,
})),
),
);
export default async function jsxToSvg(jsx: JSX.Element) {
return await satori(jsx, {
width: 480,
fonts: await fonts,
});
}
File renamed without changes.
+28
View File
@@ -0,0 +1,28 @@
import { readFileSync } from 'fs';
import satori from 'satori';
const fonts = [
{
file: require('./Roboto.ttf') as string,
weight: 400 as const,
},
{
file: require('./Roboto-Bold.ttf') as string,
weight: 700 as const,
},
{
file: require('./Roboto-Black.ttf') as string,
weight: 900 as const,
},
];
export default async function jsxToSvg(jsx: JSX.Element) {
return await satori(jsx, {
width: 480,
fonts: fonts.map(({ file, weight }) => ({
weight,
name: 'Roboto',
data: readFileSync(`${__dirname}/${file}`),
})),
});
}
+3 -3
View File
@@ -5,7 +5,7 @@ export function resolveDpm(
shell: ShellDefinition,
damageCoefficient = 1,
reloadCoefficient = 1,
interClipCoefficient = 1,
intraClipCoefficient = 1,
) {
const alpha = shell.damage.armor * damageCoefficient;
@@ -14,14 +14,14 @@ export function resolveDpm(
} else if (gun.type === 'autoLoader') {
return (
((alpha * gun.count) /
(gun.reload + (gun.count - 1) * gun.interClip * interClipCoefficient)) *
(gun.reload + (gun.count - 1) * gun.intraClip * intraClipCoefficient)) *
60
);
} else {
return (
((alpha * gun.count) /
(gun.reload.reduce((a, b) => a + b, 0) +
(gun.count - 1) * gun.interClip)) *
(gun.count - 1) * gun.intraClip)) *
60
);
}
+2 -2
View File
@@ -4,10 +4,10 @@ export function resolveReload(gun: GunDefinition) {
if (gun.type === 'regular') {
return gun.reload;
} else if (gun.type === 'autoLoader') {
return gun.reload + (gun.count - 1) * gun.interClip;
return gun.reload + (gun.count - 1) * gun.intraClip;
} else {
return (
gun.reload.reduce((a, b) => a + b, 0) + (gun.count - 1) * gun.interClip
gun.reload.reduce((a, b) => a + b, 0) + (gun.count - 1) * gun.intraClip
);
}
}
+2 -2
View File
@@ -125,13 +125,13 @@ interface GunDefinitionRegular extends GunDefinitionBase {
interface GunDefinitionAutoLoader extends GunDefinitionBase {
type: 'autoLoader';
reload: number;
interClip: number;
intraClip: number;
count: number;
}
interface GunDefinitionAutoReloader extends GunDefinitionBase {
type: 'autoReloader';
reload: number[];
interClip: number;
intraClip: number;
count: number;
}
export type ShellDefinition = {