diff --git a/packages/i18n/strings/en.json b/packages/i18n/strings/en.json index b752e8717..539136d13 100644 --- a/packages/i18n/strings/en.json +++ b/packages/i18n/strings/en.json @@ -1083,7 +1083,6 @@ "hull_traverse_speed": "Hull traverse speed", "camouflage": "Camouflage", "reload": "Reload", - "crewCount": "Crew count", "shellNormalization": "Normalization", "shellRicochet": "Ricochet", @@ -1097,6 +1096,7 @@ "caliber": "Caliber", "penetration": "Penetration", "damage": "Damage", + "damageWithoutAssault": "Damage without assault shells", "clipDamage": "Clipping potential", "moduleDamage": "Module damage", "explosionRadius": "Explosion radius", diff --git a/packages/website/src/components/Tankopedia/CharacteristicsSection/components/Characteristics/components/AssaultRangesVisualizer/components/Cursor.tsx b/packages/website/src/components/Tankopedia/CharacteristicsSection/components/Characteristics/components/AssaultRangesVisualizer/components/Cursor.tsx deleted file mode 100644 index 3ed0c304a..000000000 --- a/packages/website/src/components/Tankopedia/CharacteristicsSection/components/Characteristics/components/AssaultRangesVisualizer/components/Cursor.tsx +++ /dev/null @@ -1,66 +0,0 @@ -import { DragHandleDots2Icon } from '@radix-ui/react-icons'; -import { Box, Flex, Text } from '@radix-ui/themes'; -import { useState } from 'react'; -import { Var } from '../../../../../../../../core/radix/var'; - -export function AssaultCursor() { - const [x, setX] = useState(0.5); - - return ( - - - - - - - - - - - - - - ); -} diff --git a/packages/website/src/components/Tankopedia/CharacteristicsSection/components/Characteristics/components/AssaultRangesVisualizer/components/Cursor/index.css b/packages/website/src/components/Tankopedia/CharacteristicsSection/components/Characteristics/components/AssaultRangesVisualizer/components/Cursor/index.css new file mode 100644 index 000000000..bf7e4950c --- /dev/null +++ b/packages/website/src/components/Tankopedia/CharacteristicsSection/components/Characteristics/components/AssaultRangesVisualizer/components/Cursor/index.css @@ -0,0 +1,7 @@ +#assault-cursor { + cursor: grab; +} + +#assault-cursor:active { + cursor: grabbing; +} diff --git a/packages/website/src/components/Tankopedia/CharacteristicsSection/components/Characteristics/components/AssaultRangesVisualizer/components/Cursor/index.tsx b/packages/website/src/components/Tankopedia/CharacteristicsSection/components/Characteristics/components/AssaultRangesVisualizer/components/Cursor/index.tsx new file mode 100644 index 000000000..50f7a9ff6 --- /dev/null +++ b/packages/website/src/components/Tankopedia/CharacteristicsSection/components/Characteristics/components/AssaultRangesVisualizer/components/Cursor/index.tsx @@ -0,0 +1,107 @@ +import { DragHandleDots2Icon } from '@radix-ui/react-icons'; +import { Box, Flex, Text } from '@radix-ui/themes'; +import { useEffect, useRef, useState } from 'react'; +import { clamp } from 'three/src/math/MathUtils.js'; +import { fakeLogInverse } from '../../../../../../../../../core/blitzkit/fakeLog'; +import { Var } from '../../../../../../../../../core/radix/var'; +import { Duel } from '../../../../../../../../../stores/duel'; +import './index.css'; + +interface Props { + maxDistance: number; + maxFakeDistance: number; +} + +export function AssaultCursor({ maxDistance, maxFakeDistance }: Props) { + const [x, setX] = useState(0.5); + const cursor = useRef(null); + const mutateDuel = Duel.useMutation(); + + useEffect(() => { + let localX = x; + + function handlePointerDown(event: PointerEvent) { + event.preventDefault(); + + window.addEventListener('pointermove', handlePointerMove); + window.addEventListener('pointerup', handlePointerUp); + } + + function handlePointerMove(event: PointerEvent) { + const parent = cursor.current?.parentElement; + + if (!parent) return; + + const width = parent.clientWidth; + + setX((state) => { + localX = clamp(state + event.movementX / width, 0, 1); + return localX; + }); + } + + function handlePointerUp() { + mutateDuel((draft) => { + draft.protagonist.assaultDistance = + fakeLogInverse(localX * maxFakeDistance, 2) * maxDistance; + }); + + window.removeEventListener('pointermove', handlePointerMove); + window.removeEventListener('pointerup', handlePointerUp); + } + + cursor.current?.addEventListener('pointerdown', handlePointerDown); + + return () => { + cursor.current?.removeEventListener('pointerdown', handlePointerDown); + }; + }, []); + + return ( + + + + + + + + + + + + ); +} diff --git a/packages/website/src/components/Tankopedia/CharacteristicsSection/components/Characteristics/components/AssaultRangesVisualizer/index.tsx b/packages/website/src/components/Tankopedia/CharacteristicsSection/components/Characteristics/components/AssaultRangesVisualizer/index.tsx index b0602c2e6..0b2d8ca13 100644 --- a/packages/website/src/components/Tankopedia/CharacteristicsSection/components/Characteristics/components/AssaultRangesVisualizer/index.tsx +++ b/packages/website/src/components/Tankopedia/CharacteristicsSection/components/Characteristics/components/AssaultRangesVisualizer/index.tsx @@ -2,6 +2,7 @@ import type { AssaultRanges } from '@blitzkit/core'; import { literals } from '@blitzkit/i18n'; import { Box, Card, Flex, Text } from '@radix-ui/themes'; import { clamp } from 'three/src/math/MathUtils.js'; +import { fakeLog } from '../../../../../../../core/blitzkit/fakeLog'; import type { TankCharacteristics } from '../../../../../../../core/blitzkit/tankCharacteristics'; import { Var } from '../../../../../../../core/radix/var'; import { useLocale } from '../../../../../../../hooks/useLocale'; @@ -13,18 +14,14 @@ interface Props { } export function AssaultRangesVisualizer({ ranges: _ranges, stats }: Props) { - const maxDistance = Math.max( - ..._ranges.ranges.map((range) => range.distance), - ); + const maxDistance = _ranges.ranges.at(-1)!.distance; const ranges = _ranges.ranges.map((range) => ({ factor: range.factor, distance: range.distance, - fakeDistance: (2 / Math.PI) * Math.atan((4 * range.distance) / maxDistance), + fakeDistance: fakeLog(range.distance / maxDistance, 2), })); - const sumFakeDistances = ranges.reduce( - (total, range) => total + range.fakeDistance, - 0, - ); + const maxFakeDistance = ranges.at(-1)!.fakeDistance; + const { strings } = useLocale(); return ( @@ -51,8 +48,9 @@ export function AssaultRangesVisualizer({ ranges: _ranges, stats }: Props) { > - {ranges.map((range) => ( + {ranges.map((range, index) => ( ))} - + - {ranges.map((range, index) => ( - - { + const last = ranges[index - 1]; + const lastFakeDistance = last?.fakeDistance ?? 0; + const fakeWidth = range.fakeDistance - lastFakeDistance; + const fraction = fakeWidth / ranges.at(-1)!.fakeDistance; + + return ( + - {literals(strings.common.units.m, [ - `${Math.round(range.distance)}`, - ])} - - - ))} + + {literals(strings.common.units.m, [ + `${Math.round(range.distance)}`, + ])} + + + ); + })} diff --git a/packages/website/src/components/Tankopedia/CharacteristicsSection/components/Characteristics/components/InfoWithDelta.tsx b/packages/website/src/components/Tankopedia/CharacteristicsSection/components/Characteristics/components/InfoWithDelta.tsx index 8e7f53658..f83ba4375 100644 --- a/packages/website/src/components/Tankopedia/CharacteristicsSection/components/Characteristics/components/InfoWithDelta.tsx +++ b/packages/website/src/components/Tankopedia/CharacteristicsSection/components/Characteristics/components/InfoWithDelta.tsx @@ -118,7 +118,7 @@ export function InfoWithDelta({ tank, track: member.track, turret: member.turret, - assaultDistance: 0, + assaultDistance: member.assaultDistance, }, { equipmentDefinitions, diff --git a/packages/website/src/components/Tankopedia/CharacteristicsSection/components/Characteristics/index.tsx b/packages/website/src/components/Tankopedia/CharacteristicsSection/components/Characteristics/index.tsx index ceeb805a6..5e5de9e70 100644 --- a/packages/website/src/components/Tankopedia/CharacteristicsSection/components/Characteristics/index.tsx +++ b/packages/website/src/components/Tankopedia/CharacteristicsSection/components/Characteristics/index.tsx @@ -24,6 +24,9 @@ export function Characteristics() { const provisions = Duel.use((state) => state.protagonist.provisions); const consumables = Duel.use((state) => state.protagonist.consumables); const camouflage = Duel.use((state) => state.protagonist.camouflage); + const assaultDistance = Duel.use( + (state) => state.protagonist.assaultDistance, + ); const equipmentMatrix = Duel.use( (state) => state.protagonist.equipmentMatrix, ); @@ -58,7 +61,7 @@ export function Characteristics() { applyReactiveArmor: false, applyDynamicArmor: false, applySpallLiner: false, - assaultDistance: 0, + assaultDistance, }, { tankModelDefinition, diff --git a/packages/website/src/core/blitzkit/fakeLog.ts b/packages/website/src/core/blitzkit/fakeLog.ts new file mode 100644 index 000000000..93d44bfd0 --- /dev/null +++ b/packages/website/src/core/blitzkit/fakeLog.ts @@ -0,0 +1,7 @@ +export function fakeLog(x: number, a = 1) { + return (2 / Math.PI) * Math.atan((Math.PI * a * x) / 2); +} + +export function fakeLogInverse(y: number, a = 1) { + return (2 / (Math.PI * a)) * Math.tan((Math.PI * y) / 2); +} diff --git a/packages/website/src/core/blitzkit/tankCharacteristics.ts b/packages/website/src/core/blitzkit/tankCharacteristics.ts index e8e021203..0c152cedf 100644 --- a/packages/website/src/core/blitzkit/tankCharacteristics.ts +++ b/packages/website/src/core/blitzkit/tankCharacteristics.ts @@ -159,13 +159,12 @@ export function tankCharacteristics( [applyDynamicArmor, -0.1], [applySpallLiner && shell.type === ShellType.HE, -0.2], ); - const assaultDamageCoefficient = - gun.gun_type!.value.base.assault_ranges && - gun.gun_type!.value.base.assault_ranges.types.includes(shell.type) - ? (gun.gun_type!.value.base.assault_ranges.ranges.find( - ({ distance }) => distance >= assaultDistance, - )?.factor ?? 0) - : 1; + const assaultDamageCoefficient = gun.gun_type!.value.base.assault_ranges + ? // && gun.gun_type!.value.base.assault_ranges.types.includes(shell.type) + (gun.gun_type!.value.base.assault_ranges.ranges.find( + ({ distance }) => distance >= assaultDistance, + )?.factor ?? 0) + : 1; const moduleDamageCoefficient = coefficient([hasTungsten, 0.15]) * assaultDamageCoefficient; const reloadCoefficient = diff --git a/packages/website/src/core/blitzkit/tankToDuelMember.ts b/packages/website/src/core/blitzkit/tankToDuelMember.ts index ab0d96a92..9e6c9dc3e 100644 --- a/packages/website/src/core/blitzkit/tankToDuelMember.ts +++ b/packages/website/src/core/blitzkit/tankToDuelMember.ts @@ -40,5 +40,6 @@ export function tankToDuelMember( yaw, pitch, turret, + assaultDistance: 0, } satisfies DuelMember; } diff --git a/packages/website/src/stores/duel/index.ts b/packages/website/src/stores/duel/index.ts index 132c5d789..310e5c703 100644 --- a/packages/website/src/stores/duel/index.ts +++ b/packages/website/src/stores/duel/index.ts @@ -39,6 +39,7 @@ export interface DuelMember { provisions: number[]; camouflage: boolean; cooldownBooster: number; + assaultDistance: number; } export interface DuelStore {