feat: localize tankopedia chars

This commit is contained in:
tresabhi committed 2025-01-14 20:13:38 -06:00
1 parent 2c365cdea0
commit c4f1d9f3b0
5 files changed
+322 -146

No files matched your search

@@ -13,13 +13,13 @@ export const SHELL_NAMES: Record<ShellType, string> = {
[ShellType.HEAT]: 'HEAT', [ShellType.HEAT]: 'HEAT',
[ShellType.HE]: 'HE', [ShellType.HE]: 'HE',
}; };
export const CREW_MEMBER_NAMES: Record<CrewType, string> = { export const CREW_MEMBER_NAMES = {
[CrewType.COMMANDER]: 'Commander', [CrewType.COMMANDER]: 'commander',
[CrewType.DRIVER]: 'Driver', [CrewType.DRIVER]: 'driver',
[CrewType.GUNNER]: 'Gunner', [CrewType.GUNNER]: 'gunner',
[CrewType.LOADER]: 'Loader', [CrewType.LOADER]: 'loader',
[CrewType.RADIOMAN]: 'Radioman', [CrewType.RADIOMAN]: 'radioman',
}; } as const;
export const GUN_TYPE_NAMES: Record< export const GUN_TYPE_NAMES: Record<
Exclude<GunDefinition['gun_type'], undefined>['$case'], Exclude<GunDefinition['gun_type'], undefined>['$case'],
string string
+113
View File
@@ -973,6 +973,119 @@
"miscellaneous": { "miscellaneous": {
"title": "Miscellaneous" "title": "Miscellaneous"
} }
},
"characteristics": {
"title": "Characteristics",
"compare": {
"label": "Compare against",
"class": "Tier %s1 %s2",
"tier": "All of tier %s1",
"all": "All tanks"
},
"values": {
"shell_index": "Shell %s1",
"at_distance": "At %s1m",
"at_distance_slider_label": "Distance",
"dispersion_at_distance": "Dispersion at %s1m",
"gun_flexibility": "Gun flexibility",
"speed": "Speed",
"terrain_coefficients": "Terrain coefficients",
"raw_terrain_coefficients": "Raw terrain coefficients",
"power_to_weight_ratio": "Power to weight ratio",
"hull_traverse_speed": "Hull traverse speed",
"camouflage": "Camouflage",
"crewCount": "Crew count",
"shellNormalization": "Normalization",
"shellRicochet": "Ricochet",
"dpm": "DPM",
"dpmEffective": "Effective at 60s",
"shells": "Shells",
"mostOptimalShellIndex": "Most optimal shell",
"shellReloads": "Shell reloads",
"shellReload": "Shell reload",
"intraClip": "Intra-clip",
"caliber": "Caliber",
"penetration": "Penetration",
"damage": "Damage",
"clipDamage": "Clipping potential",
"moduleDamage": "Module damage",
"explosionRadius": "Explosion radius",
"shellVelocity": "Shell velocity",
"aimTime": "Aim time",
"dispersion": "Still",
"dispersionMoving": "Moving",
"dispersionHullTraversing": "Hull traversing",
"dispersionTurretTraversing": "Turret traversing",
"dispersionShooting": "Shooting",
"dispersionGunDamaged": "Gun damaged",
"gunDepression": "Depression",
"gunElevation": "Elevation",
"gunFrontalDepression": "Frontal depression",
"gunFrontalElevation": "Frontal elevation",
"gunRearDepression": "Rear depression",
"gunRearElevation": "Rear elevation",
"azimuthLeft": "Azimuth left",
"azimuthRight": "Azimuth right",
"speedForwards": "Forwards",
"speedBackwards": "Backwards",
"hardTerrainCoefficient": "Hard",
"hardTerrainCoefficientRaw": "Hard",
"mediumTerrainCoefficient": "Medium",
"mediumTerrainCoefficientRaw": "Medium",
"softTerrainCoefficient": "Soft",
"softTerrainCoefficientRaw": "Soft",
"enginePower": "Engine power",
"powerToWeightRatioHardTerrain": "Hard",
"powerToWeightRatioMediumTerrain": "Medium",
"powerToWeightRatioSoftTerrain": "Soft",
"weight": "Weight",
"turretTraverseSpeed": "Turret traverse speed",
"gunTraverseSpeed": "Gun traverse speed",
"hullTraverseHardTerrain": "Hard",
"hullTraverseMediumTerrain": "Medium",
"hullTraverseSoftTerrain": "Soft",
"health": "Health",
"fireChance": "Fire chance",
"viewRange": "View range",
"camouflageStill": "Still",
"camouflageMoving": "Moving",
"camouflageShootingStill": "Still",
"camouflageShootingMoving": "Moving",
"camouflageCaughtOnFire": "Caught on fire",
"width": "Width",
"height": "Height",
"length": "Length",
"volume": "Volume",
"shellRange": "Shell range",
"shellCapacity": "Shell capacity",
"gunType": "Gun type",
"penetrationAt250m": "Penetration at 250m"
}
},
"firepower": {
"title": "Firepower"
},
"crew": {
"title": "Crew training",
"info": "represents the other roles a crew member can take.",
"count": "Crew count",
"commander": "Commander",
"gunner": "Gunner",
"driver": "Driver",
"radioman": "Radioman",
"loader": "Loader"
},
"maneuverability": {
"title": "Maneuverability"
},
"survivability": {
"title": "Survivability"
} }
}, },
"compare": { "compare": {
@@ -1,5 +1,6 @@
import { TIER_ROMAN_NUMERALS } from '@blitzkit/core'; import { TIER_ROMAN_NUMERALS } from '@blitzkit/core';
import { Flex, Heading, SegmentedControl, Text } from '@radix-ui/themes'; import { Flex, Heading, SegmentedControl, Text } from '@radix-ui/themes';
import { literals } from '../../../../../../core/i18n/literals';
import { useLocale } from '../../../../../../hooks/useLocale'; import { useLocale } from '../../../../../../hooks/useLocale';
import { Duel } from '../../../../../../stores/duel'; import { Duel } from '../../../../../../stores/duel';
import { import {
@@ -21,9 +22,13 @@ export function CharacteristicsHeading() {
gap="2" gap="2"
direction="column" direction="column"
> >
<Heading mb="2">Characteristics</Heading> <Heading mb="2">
{strings.website.tools.tankopedia.characteristics.title}
</Heading>
<Text color="gray">Compare against</Text> <Text color="gray">
{strings.website.tools.tankopedia.characteristics.compare.label}
</Text>
<SegmentedControl.Root <SegmentedControl.Root
size={{ initial: '1', md: '2' }} size={{ initial: '1', md: '2' }}
value={`${relativeAgainst}`} value={`${relativeAgainst}`}
@@ -34,14 +39,22 @@ export function CharacteristicsHeading() {
}} }}
> >
<SegmentedControl.Item value={`${TankopediaRelativeAgainst.Class}`}> <SegmentedControl.Item value={`${TankopediaRelativeAgainst.Class}`}>
Tier {TIER_ROMAN_NUMERALS[tank.tier]}{' '} {literals(
{strings.common.tank_class_short_plural_lowercase[tank.class]} strings.website.tools.tankopedia.characteristics.compare.class,
[
TIER_ROMAN_NUMERALS[tank.tier],
strings.common.tank_class_short_plural_lowercase[tank.class],
],
)}
</SegmentedControl.Item> </SegmentedControl.Item>
<SegmentedControl.Item value={`${TankopediaRelativeAgainst.Tier}`}> <SegmentedControl.Item value={`${TankopediaRelativeAgainst.Tier}`}>
All of tier {TIER_ROMAN_NUMERALS[tank.tier]} {literals(
strings.website.tools.tankopedia.characteristics.compare.tier,
[TIER_ROMAN_NUMERALS[tank.tier]],
)}
</SegmentedControl.Item> </SegmentedControl.Item>
<SegmentedControl.Item value={`${TankopediaRelativeAgainst.All}`}> <SegmentedControl.Item value={`${TankopediaRelativeAgainst.All}`}>
All tanks {strings.website.tools.tankopedia.characteristics.compare.all}
</SegmentedControl.Item> </SegmentedControl.Item>
</SegmentedControl.Root> </SegmentedControl.Root>
</Flex> </Flex>
@@ -1,6 +1,6 @@
import { createDefaultSkills } from '@blitzkit/core'; import { createDefaultSkills } from '@blitzkit/core';
import { Flex, Progress, Text } from '@radix-ui/themes'; import { Flex, Progress, Text } from '@radix-ui/themes';
import { useMemo, type ComponentProps } from 'react'; import { useMemo, type ComponentProps, type ReactNode } from 'react';
import { awaitableEquipmentDefinitions } from '../../../../../../core/awaitables/equipmentDefinitions'; import { awaitableEquipmentDefinitions } from '../../../../../../core/awaitables/equipmentDefinitions';
import { awaitableModelDefinitions } from '../../../../../../core/awaitables/modelDefinitions'; import { awaitableModelDefinitions } from '../../../../../../core/awaitables/modelDefinitions';
import { awaitableProvisionDefinitions } from '../../../../../../core/awaitables/provisionDefinitions'; import { awaitableProvisionDefinitions } from '../../../../../../core/awaitables/provisionDefinitions';
@@ -12,6 +12,7 @@ import {
} from '../../../../../../core/blitzkit/tankCharacteristics'; } from '../../../../../../core/blitzkit/tankCharacteristics';
import { tankToDuelMember } from '../../../../../../core/blitzkit/tankToDuelMember'; import { tankToDuelMember } from '../../../../../../core/blitzkit/tankToDuelMember';
import { useDelta } from '../../../../../../hooks/useDelta'; import { useDelta } from '../../../../../../hooks/useDelta';
import { useLocale } from '../../../../../../hooks/useLocale';
import { Duel } from '../../../../../../stores/duel'; import { Duel } from '../../../../../../stores/duel';
import { import {
TankopediaEphemeral, TankopediaEphemeral,
@@ -19,13 +20,18 @@ import {
} from '../../../../../../stores/tankopediaEphemeral'; } from '../../../../../../stores/tankopediaEphemeral';
import { Info, type InfoProps } from './Info'; import { Info, type InfoProps } from './Info';
interface InfoWithDeltaProps extends InfoProps { type InfoWithDeltaProps = Omit<InfoProps, 'name'> & {
stats: TankCharacteristics; stats: TankCharacteristics;
value:
| keyof TankCharacteristics
| ((tank: TankCharacteristics) => number | undefined);
noRanking?: boolean; noRanking?: boolean;
} } & (
| {
value: keyof TankCharacteristics;
}
| {
value: (tank: TankCharacteristics) => number | undefined;
name: ReactNode;
}
);
const [ const [
tankDefinitions, tankDefinitions,
@@ -42,18 +48,20 @@ const [
]); ]);
export function InfoWithDelta({ export function InfoWithDelta({
value,
stats, stats,
indent, indent,
noRanking, noRanking,
deltaType, deltaType,
...props ...props
}: InfoWithDeltaProps) { }: InfoWithDeltaProps) {
const { strings } = useLocale();
const relativeAgainst = TankopediaEphemeral.use( const relativeAgainst = TankopediaEphemeral.use(
(state) => state.relativeAgainst, (state) => state.relativeAgainst,
); );
const uhWhatDoICallThisVariable = const uhWhatDoICallThisVariable =
typeof value === 'function' ? value(stats)! : (stats[value] as number); typeof props.value === 'function'
? props.value(stats)!
: (stats[props.value] as number);
const delta = useDelta(uhWhatDoICallThisVariable); const delta = useDelta(uhWhatDoICallThisVariable);
const protagonistTank = Duel.use((state) => state.protagonist.tank); const protagonistTank = Duel.use((state) => state.protagonist.tank);
const others = useMemo(() => { const others = useMemo(() => {
@@ -102,14 +110,18 @@ export function InfoWithDelta({
}) })
.filter((tank) => { .filter((tank) => {
const othersValue = const othersValue =
typeof value === 'function' ? value(tank)! : (tank[value] as number); typeof props.value === 'function'
? props.value(tank)!
: (tank[props.value] as number);
return othersValue !== undefined; return othersValue !== undefined;
}); });
}, [relativeAgainst]); }, [relativeAgainst]);
const betterTanks = others.filter((tank) => { const betterTanks = others.filter((tank) => {
const othersValue = const othersValue =
typeof value === 'function' ? value(tank)! : (tank[value] as number); typeof props.value === 'function'
? props.value(tank)!
: (tank[props.value] as number);
if (othersValue === undefined) return false; if (othersValue === undefined) return false;
return deltaType === 'lowerIsBetter' return deltaType === 'lowerIsBetter'
@@ -126,7 +138,19 @@ export function InfoWithDelta({
return ( return (
<Flex direction="column"> <Flex direction="column">
<Info deltaType={deltaType} indent={indent} {...props} delta={delta}> <Info
deltaType={deltaType}
indent={indent}
{...props}
name={
'name' in props
? props.name
: strings.website.tools.tankopedia.characteristics.values[
props.value
]
}
delta={delta}
>
{uhWhatDoICallThisVariable} {uhWhatDoICallThisVariable}
</Info> </Info>
@@ -26,6 +26,7 @@ import { awaitableEquipmentDefinitions } from '../../../../../core/awaitables/eq
import { awaitableProvisionDefinitions } from '../../../../../core/awaitables/provisionDefinitions'; import { awaitableProvisionDefinitions } from '../../../../../core/awaitables/provisionDefinitions';
import { applyPitchYawLimits } from '../../../../../core/blitz/applyPitchYawLimits'; import { applyPitchYawLimits } from '../../../../../core/blitz/applyPitchYawLimits';
import { tankCharacteristics } from '../../../../../core/blitzkit/tankCharacteristics'; import { tankCharacteristics } from '../../../../../core/blitzkit/tankCharacteristics';
import { literals } from '../../../../../core/i18n/literals';
import { useEquipment } from '../../../../../hooks/useEquipment'; import { useEquipment } from '../../../../../hooks/useEquipment';
import { useLocale } from '../../../../../hooks/useLocale'; import { useLocale } from '../../../../../hooks/useLocale';
import { useTankModelDefinition } from '../../../../../hooks/useTankModelDefinition'; import { useTankModelDefinition } from '../../../../../hooks/useTankModelDefinition';
@@ -40,7 +41,7 @@ const [equipmentDefinitions, provisionDefinitions] = await Promise.all([
]); ]);
export function Characteristics() { export function Characteristics() {
const { unwrap } = useLocale(); const { unwrap, strings } = useLocale();
const mutateDuel = Duel.useMutation(); const mutateDuel = Duel.useMutation();
const crewSkills = TankopediaEphemeral.use((state) => state.skills); const crewSkills = TankopediaEphemeral.use((state) => state.skills);
const penetrationDistanceInput = useRef<HTMLInputElement>(null); const penetrationDistanceInput = useRef<HTMLInputElement>(null);
@@ -144,7 +145,9 @@ export function Characteristics() {
<Flex direction="column" gap="8" style={{ flex: 1 }}> <Flex direction="column" gap="8" style={{ flex: 1 }}>
<Flex direction="column" gap="2"> <Flex direction="column" gap="2">
<Flex align="center" gap="4"> <Flex align="center" gap="4">
<Heading size="5">Firepower</Heading> <Heading size="5">
{strings.website.tools.tankopedia.firepower.title}
</Heading>
<Flex> <Flex>
{gun.gun_type!.value.base.shells.map((thisShell, shellIndex) => ( {gun.gun_type!.value.base.shells.map((thisShell, shellIndex) => (
@@ -184,10 +187,15 @@ export function Characteristics() {
))} ))}
</Flex> </Flex>
</Flex> </Flex>
<Info name="Gun type">{GUN_TYPE_NAMES[gun.gun_type!.$case]}</Info> <Info
name={
strings.website.tools.tankopedia.characteristics.values.gunType
}
>
{GUN_TYPE_NAMES[gun.gun_type!.$case]}
</Info>
<InfoWithDelta <InfoWithDelta
stats={stats} stats={stats}
name="DPM"
decimals={0} decimals={0}
unit="hp / min" unit="hp / min"
value="dpm" value="dpm"
@@ -197,26 +205,41 @@ export function Characteristics() {
stats={stats} stats={stats}
decimals={0} decimals={0}
indent indent
name="Effective at 60s"
unit="hp / min" unit="hp / min"
value="dpmEffective" value="dpmEffective"
/> />
)} )}
{gun.gun_type!.$case !== 'regular' && ( {gun.gun_type!.$case !== 'regular' && (
<InfoWithDelta stats={stats} name="Shells" value="shells" /> <InfoWithDelta stats={stats} value="shells" />
)} )}
{gun.gun_type!.$case === 'auto_reloader' ? ( {gun.gun_type!.$case === 'auto_reloader' ? (
<> <>
<Info indent name="Most optimal shell index"> <Info
indent
name={
strings.website.tools.tankopedia.characteristics.values
.mostOptimalShellIndex
}
>
{stats.mostOptimalShellIndex! + 1} {stats.mostOptimalShellIndex! + 1}
</Info> </Info>
<Info name="Shell reloads" unit="s" /> <Info
name={
strings.website.tools.tankopedia.characteristics.values
.shellReloads
}
unit="s"
/>
{stats.shellReloads!.map((reload, index) => ( {stats.shellReloads!.map((reload, index) => (
<InfoWithDelta <InfoWithDelta
stats={stats} stats={stats}
key={index} key={index}
indent indent
name={`Shell ${index + 1}`} name={literals(
strings.website.tools.tankopedia.characteristics.values
.shell_index,
[`${index + 1}`],
)}
decimals={2} decimals={2}
deltaType="lowerIsBetter" deltaType="lowerIsBetter"
noRanking noRanking
@@ -228,7 +251,6 @@ export function Characteristics() {
<InfoWithDelta <InfoWithDelta
stats={stats} stats={stats}
decimals={2} decimals={2}
name="Reload"
unit="s" unit="s"
deltaType="lowerIsBetter" deltaType="lowerIsBetter"
value="shellReload" value="shellReload"
@@ -240,7 +262,6 @@ export function Characteristics() {
stats={stats} stats={stats}
indent indent
decimals={2} decimals={2}
name="Intra-clip"
unit="s" unit="s"
deltaType="lowerIsBetter" deltaType="lowerIsBetter"
value="intraClip" value="intraClip"
@@ -249,7 +270,6 @@ export function Characteristics() {
<InfoWithDelta <InfoWithDelta
stats={stats} stats={stats}
decimals={0} decimals={0}
name="Penetration"
unit="mm" unit="mm"
value="penetration" value="penetration"
/> />
@@ -259,7 +279,11 @@ export function Characteristics() {
stats={stats} stats={stats}
indent indent
decimals={0} decimals={0}
name={`At ${penetrationDistance}m`} name={literals(
strings.website.tools.tankopedia.characteristics.values
.at_distance,
[`${penetrationDistance}`],
)}
noRanking noRanking
value={() => value={() =>
lerp( lerp(
@@ -272,7 +296,12 @@ export function Characteristics() {
} }
/> />
<Flex align="center" gap="2" style={{ paddingLeft: 24 }}> <Flex align="center" gap="2" style={{ paddingLeft: 24 }}>
<Text color="gray">Distance</Text> <Text color="gray">
{
strings.website.tools.tankopedia.characteristics.values
.at_distance_slider_label
}
</Text>
<Slider <Slider
key={penetrationDistance} key={penetrationDistance}
min={0} min={0}
@@ -310,17 +339,10 @@ export function Characteristics() {
</Flex> </Flex>
</> </>
)} )}
<InfoWithDelta <InfoWithDelta stats={stats} unit="hp" decimals={0} value="damage" />
stats={stats}
name="Damage"
unit="hp"
decimals={0}
value="damage"
/>
{gun.gun_type!.$case !== 'regular' && ( {gun.gun_type!.$case !== 'regular' && (
<InfoWithDelta <InfoWithDelta
stats={stats} stats={stats}
name="Clipping potential"
indent indent
decimals={0} decimals={0}
value="clipDamage" value="clipDamage"
@@ -328,7 +350,6 @@ export function Characteristics() {
)} )}
<InfoWithDelta <InfoWithDelta
stats={stats} stats={stats}
name="Module damage"
unit="hp" unit="hp"
decimals={0} decimals={0}
value="moduleDamage" value="moduleDamage"
@@ -336,23 +357,15 @@ export function Characteristics() {
{isExplosive(shell.type) && ( {isExplosive(shell.type) && (
<InfoWithDelta <InfoWithDelta
stats={stats} stats={stats}
name="Splash radius"
unit="m" unit="m"
noRanking noRanking
decimals={0} decimals={0}
value="explosionRadius" value="explosionRadius"
/> />
)} )}
<InfoWithDelta stats={stats} decimals={0} unit="mm" value="caliber" />
<InfoWithDelta <InfoWithDelta
stats={stats} stats={stats}
name="Caliber"
decimals={0}
unit="mm"
value="caliber"
/>
<InfoWithDelta
stats={stats}
name="Normalization"
decimals={0} decimals={0}
unit="°" unit="°"
noRanking noRanking
@@ -361,7 +374,6 @@ export function Characteristics() {
{!isExplosive(shell.type) && ( {!isExplosive(shell.type) && (
<InfoWithDelta <InfoWithDelta
stats={stats} stats={stats}
name="Ricochet"
noRanking noRanking
decimals={0} decimals={0}
deltaType="lowerIsBetter" deltaType="lowerIsBetter"
@@ -371,39 +383,35 @@ export function Characteristics() {
)} )}
<InfoWithDelta <InfoWithDelta
stats={stats} stats={stats}
name="Shell velocity"
unit="m/s" unit="m/s"
decimals={0} decimals={0}
value="shellVelocity" value="shellVelocity"
/> />
<InfoWithDelta <InfoWithDelta
stats={stats} stats={stats}
name="Shell range"
unit="m/s" unit="m/s"
decimals={0} decimals={0}
value="shellRange" value="shellRange"
/> />
<InfoWithDelta <InfoWithDelta stats={stats} decimals={0} value="shellCapacity" />
stats={stats}
name="Shell capacity"
unit="m/s"
decimals={0}
value="shellCapacity"
/>
<InfoWithDelta <InfoWithDelta
stats={stats} stats={stats}
decimals={2} decimals={2}
name="Aim time"
unit="s" unit="s"
deltaType="lowerIsBetter" deltaType="lowerIsBetter"
value="aimTime" value="aimTime"
/> />
<Info name="Dispersion at 100m" /> <Info
name={literals(
strings.website.tools.tankopedia.characteristics.values
.dispersion_at_distance,
['100'],
)}
/>
<InfoWithDelta <InfoWithDelta
stats={stats} stats={stats}
decimals={3} decimals={3}
indent indent
name="Still"
unit="m" unit="m"
deltaType="lowerIsBetter" deltaType="lowerIsBetter"
value="dispersion" value="dispersion"
@@ -413,7 +421,6 @@ export function Characteristics() {
prefix="+" prefix="+"
decimals={3} decimals={3}
indent indent
name="Moving"
deltaType="lowerIsBetter" deltaType="lowerIsBetter"
value="dispersionMoving" value="dispersionMoving"
/> />
@@ -422,7 +429,6 @@ export function Characteristics() {
decimals={3} decimals={3}
prefix="+" prefix="+"
indent indent
name="Hull traversing"
deltaType="lowerIsBetter" deltaType="lowerIsBetter"
value="dispersionHullTraversing" value="dispersionHullTraversing"
/> />
@@ -431,7 +437,6 @@ export function Characteristics() {
decimals={3} decimals={3}
prefix="+" prefix="+"
indent indent
name="Turret traversing"
deltaType="lowerIsBetter" deltaType="lowerIsBetter"
value="dispersionTurretTraversing" value="dispersionTurretTraversing"
/> />
@@ -440,7 +445,6 @@ export function Characteristics() {
decimals={3} decimals={3}
prefix="+" prefix="+"
indent indent
name="After shooting"
deltaType="lowerIsBetter" deltaType="lowerIsBetter"
value="dispersionShooting" value="dispersionShooting"
/> />
@@ -449,24 +453,26 @@ export function Characteristics() {
decimals={1} decimals={1}
prefix="x " prefix="x "
indent indent
name="Gun damaged"
unit="scalar"
deltaType="lowerIsBetter" deltaType="lowerIsBetter"
value="dispersionGunDamaged" value="dispersionGunDamaged"
/> />
<Info name="Gun flexibility" unit="°" /> <Info
name={
strings.website.tools.tankopedia.characteristics.values
.gun_flexibility
}
unit="°"
/>
<InfoWithDelta <InfoWithDelta
value="gunDepression" value="gunDepression"
stats={stats} stats={stats}
decimals={1} decimals={1}
indent indent
name="Depression"
/> />
<InfoWithDelta <InfoWithDelta
stats={stats} stats={stats}
decimals={1} decimals={1}
indent indent
name="Elevation"
value="gunElevation" value="gunElevation"
/> />
{gunModelDefinition.pitch.front && ( {gunModelDefinition.pitch.front && (
@@ -475,14 +481,12 @@ export function Characteristics() {
stats={stats} stats={stats}
decimals={1} decimals={1}
indent indent
name="Frontal depression"
value="gunFrontalDepression" value="gunFrontalDepression"
/> />
<InfoWithDelta <InfoWithDelta
stats={stats} stats={stats}
decimals={1} decimals={1}
indent indent
name="Frontal elevation"
value="gunFrontalElevation" value="gunFrontalElevation"
/> />
</> </>
@@ -493,14 +497,12 @@ export function Characteristics() {
stats={stats} stats={stats}
decimals={1} decimals={1}
indent indent
name="Rear depression"
value="gunRearDepression" value="gunRearDepression"
/> />
<InfoWithDelta <InfoWithDelta
stats={stats} stats={stats}
decimals={1} decimals={1}
indent indent
name="Rear elevation"
value="gunRearElevation" value="gunRearElevation"
/> />
</> </>
@@ -511,14 +513,12 @@ export function Characteristics() {
stats={stats} stats={stats}
decimals={1} decimals={1}
indent indent
name="Azimuth left"
value="azimuthLeft" value="azimuthLeft"
/> />
<InfoWithDelta <InfoWithDelta
stats={stats} stats={stats}
decimals={1} decimals={1}
indent indent
name="Azimuth right"
value="azimuthRight" value="azimuthRight"
/> />
</> </>
@@ -527,7 +527,9 @@ export function Characteristics() {
<Flex direction="column" gap="2"> <Flex direction="column" gap="2">
<Flex gap="2" align="center"> <Flex gap="2" align="center">
<Heading size="5">Crew training</Heading> <Heading size="5">
{strings.website.tools.tankopedia.crew.title}
</Heading>
<Popover.Root> <Popover.Root>
<Popover.Trigger> <Popover.Trigger>
@@ -539,20 +541,13 @@ export function Characteristics() {
<Popover.Content> <Popover.Content>
<Flex gap="1" align="center"> <Flex gap="1" align="center">
<AccessibilityIcon /> <AccessibilityIcon />
<Text> <Text>{strings.website.tools.tankopedia.crew.info}</Text>
represents the other roles a crew member can take.
</Text>
</Flex> </Flex>
</Popover.Content> </Popover.Content>
</Popover.Root> </Popover.Root>
</Flex> </Flex>
<InfoWithDelta <InfoWithDelta value="crewCount" stats={stats} decimals={0} />
value="crewCount"
stats={stats}
name="Crew count"
decimals={0}
/>
{tank.crew.map((member) => { {tank.crew.map((member) => {
return ( return (
@@ -560,8 +555,16 @@ export function Characteristics() {
<InfoWithDelta <InfoWithDelta
stats={stats} stats={stats}
key={`${member.type}-root`} key={`${member.type}-root`}
name={`${CREW_MEMBER_NAMES[member.type]}${ name={`${
member.count > 1 ? ` x ${member.count}` : '' strings.website.tools.tankopedia.crew[
CREW_MEMBER_NAMES[member.type]
]
}${
member.count > 1
? ` ${literals(strings.common.units.x, [
`${member.count}`,
])}`
: ''
}`} }`}
unit="%" unit="%"
decimals={0} decimals={0}
@@ -586,7 +589,11 @@ export function Characteristics() {
<AccessibilityIcon /> <AccessibilityIcon />
{member.substitute {member.substitute
.map((sub, index) => .map((sub, index) =>
index === 0 ? CREW_MEMBER_NAMES[sub] : sub, index === 0
? strings.website.tools.tankopedia.crew[
CREW_MEMBER_NAMES[sub]
]
: sub,
) )
.join(', ')} .join(', ')}
</Flex> </Flex>
@@ -604,52 +611,51 @@ export function Characteristics() {
<Flex direction="column" gap="8" style={{ flex: 1 }}> <Flex direction="column" gap="8" style={{ flex: 1 }}>
<Flex direction="column" gap="2"> <Flex direction="column" gap="2">
<Heading size="5">Maneuverability</Heading> <Heading size="5">
<Info name="Speed" unit="kph" /> {strings.website.tools.tankopedia.maneuverability.title}
</Heading>
<Info
name={strings.website.tools.tankopedia.characteristics.values.speed}
unit="kph"
/>
<InfoWithDelta <InfoWithDelta
value="speedForwards" value="speedForwards"
stats={stats} stats={stats}
decimals={0} decimals={0}
indent indent
name="Forwards"
/> />
<InfoWithDelta <InfoWithDelta
value="speedBackwards" value="speedBackwards"
stats={stats} stats={stats}
decimals={0} decimals={0}
indent indent
name="Backwards"
/>
<InfoWithDelta
stats={stats}
decimals={0}
name="Engine power"
unit="hp"
value="enginePower"
/> />
<InfoWithDelta stats={stats} decimals={0} value="enginePower" />
<InfoWithDelta <InfoWithDelta
stats={stats} stats={stats}
decimals={1} decimals={1}
name="Weight"
unit="tn" unit="tn"
deltaType="lowerIsBetter" deltaType="lowerIsBetter"
value="weight" value="weight"
/> />
<Info name="Terrain coefficients" /> <Info
name={
strings.website.tools.tankopedia.characteristics.values
.terrain_coefficients
}
/>
<InfoWithDelta <InfoWithDelta
value="hardTerrainCoefficient" value="hardTerrainCoefficient"
stats={stats} stats={stats}
decimals={0} decimals={0}
unit="%" unit="%"
indent indent
name="Hard"
/> />
<InfoWithDelta <InfoWithDelta
stats={stats} stats={stats}
decimals={0} decimals={0}
unit="%" unit="%"
indent indent
name="Medium"
value="mediumTerrainCoefficient" value="mediumTerrainCoefficient"
/> />
<InfoWithDelta <InfoWithDelta
@@ -658,9 +664,14 @@ export function Characteristics() {
decimals={0} decimals={0}
unit="%" unit="%"
indent indent
name="Soft"
/> />
<Info name="Raw terrain coefficients" deltaType="lowerIsBetter" /> <Info
name={
strings.website.tools.tankopedia.characteristics.values
.raw_terrain_coefficients
}
deltaType="lowerIsBetter"
/>
<InfoWithDelta <InfoWithDelta
value="hardTerrainCoefficientRaw" value="hardTerrainCoefficientRaw"
stats={stats} stats={stats}
@@ -668,14 +679,12 @@ export function Characteristics() {
unit="%" unit="%"
indent indent
deltaType="lowerIsBetter" deltaType="lowerIsBetter"
name="Hard"
/> />
<InfoWithDelta <InfoWithDelta
stats={stats} stats={stats}
decimals={2} decimals={2}
unit="%" unit="%"
indent indent
name="Medium"
deltaType="lowerIsBetter" deltaType="lowerIsBetter"
value="mediumTerrainCoefficientRaw" value="mediumTerrainCoefficientRaw"
/> />
@@ -684,75 +693,77 @@ export function Characteristics() {
decimals={2} decimals={2}
unit="%" unit="%"
indent indent
name="Soft"
deltaType="lowerIsBetter" deltaType="lowerIsBetter"
value="softTerrainCoefficientRaw" value="softTerrainCoefficientRaw"
/> />
<Info name="Power to weight ratio" unit="hp/tn" /> <Info
name={
strings.website.tools.tankopedia.characteristics.values
.power_to_weight_ratio
}
unit="hp/tn"
/>
<InfoWithDelta <InfoWithDelta
stats={stats} stats={stats}
decimals={1} decimals={1}
indent indent
name="On hard terrain"
value="powerToWeightRatioHardTerrain" value="powerToWeightRatioHardTerrain"
/> />
<InfoWithDelta <InfoWithDelta
stats={stats} stats={stats}
decimals={1} decimals={1}
indent indent
name="On medium terrain"
value="powerToWeightRatioMediumTerrain" value="powerToWeightRatioMediumTerrain"
/> />
<InfoWithDelta <InfoWithDelta
stats={stats} stats={stats}
decimals={1} decimals={1}
indent indent
name="On soft terrain"
value="powerToWeightRatioSoftTerrain" value="powerToWeightRatioSoftTerrain"
/> />
<InfoWithDelta <InfoWithDelta
stats={stats} stats={stats}
name="Turret traverse speed"
unit="°/s" unit="°/s"
decimals={1} decimals={1}
value="turretTraverseSpeed" value="turretTraverseSpeed"
/> />
<Info name="Hull traverse speed" unit="°/s" /> <Info
name={
strings.website.tools.tankopedia.characteristics.values
.hull_traverse_speed
}
unit="°/s"
/>
<InfoWithDelta <InfoWithDelta
stats={stats} stats={stats}
decimals={1} decimals={1}
indent indent
name="On hard terrain"
value="hullTraverseHardTerrain" value="hullTraverseHardTerrain"
/> />
<InfoWithDelta <InfoWithDelta
stats={stats} stats={stats}
decimals={1} decimals={1}
indent indent
name="On medium terrain"
value="hullTraverseMediumTerrain" value="hullTraverseMediumTerrain"
/> />
<InfoWithDelta <InfoWithDelta
stats={stats} stats={stats}
decimals={1} decimals={1}
indent indent
name="On soft terrain"
value="hullTraverseSoftTerrain" value="hullTraverseSoftTerrain"
/> />
</Flex> </Flex>
<Flex direction="column" gap="2"> <Flex direction="column" gap="2">
<Heading size="5">Survivability</Heading> <Heading size="5">
<InfoWithDelta {strings.website.tools.tankopedia.survivability.title}
value="health" </Heading>
stats={stats} <InfoWithDelta value="health" stats={stats} unit="hp" decimals={0} />
name="Health"
unit="hp"
decimals={0}
/>
<InfoWithDelta <InfoWithDelta
stats={stats} stats={stats}
name="Fire chance" name={
strings.website.tools.tankopedia.characteristics.values.fireChance
}
unit="%" unit="%"
deltaType="lowerIsBetter" deltaType="lowerIsBetter"
decimals={0} decimals={0}
@@ -761,48 +772,66 @@ export function Characteristics() {
<InfoWithDelta <InfoWithDelta
value="viewRange" value="viewRange"
stats={stats} stats={stats}
name="View range"
unit="m" unit="m"
decimals={0} decimals={0}
/> />
<Info name="Camouflage" unit="%" /> <Info
name={
strings.website.tools.tankopedia.characteristics.values.camouflage
}
unit="%"
/>
<InfoWithDelta <InfoWithDelta
value={(stats) => stats.camouflageStill * 100} value={(stats) => stats.camouflageStill * 100}
stats={stats} stats={stats}
indent indent
name="Still" name={
strings.website.tools.tankopedia.characteristics.values
.camouflageStill
}
decimals={2} decimals={2}
/> />
<InfoWithDelta <InfoWithDelta
value={(stats) => stats.camouflageMoving * 100} value={(stats) => stats.camouflageMoving * 100}
stats={stats} stats={stats}
indent indent
name="Moving" name={
strings.website.tools.tankopedia.characteristics.values
.camouflageMoving
}
decimals={2} decimals={2}
/> />
<InfoWithDelta <InfoWithDelta
stats={stats} stats={stats}
indent indent
name="Shooting still" name={
strings.website.tools.tankopedia.characteristics.values
.camouflageShootingStill
}
decimals={2} decimals={2}
value={(stats) => stats.camouflageShootingStill * 100} value={(stats) => stats.camouflageShootingStill * 100}
/> />
<InfoWithDelta <InfoWithDelta
stats={stats} stats={stats}
indent indent
name="Shooting moving" name={
strings.website.tools.tankopedia.characteristics.values
.camouflageShootingMoving
}
decimals={2} decimals={2}
value={(stats) => stats.camouflageShootingMoving * 100} value={(stats) => stats.camouflageShootingMoving * 100}
/> />
<InfoWithDelta <InfoWithDelta
stats={stats} stats={stats}
indent indent
name="Caught on fire" name={
strings.website.tools.tankopedia.characteristics.values
.camouflageCaughtOnFire
}
decimals={2} decimals={2}
value={(stats) => stats.camouflageCaughtOnFire * 100} value={(stats) => stats.camouflageCaughtOnFire * 100}
/> />
<InfoWithDelta <InfoWithDelta
name="Width"
unit="m" unit="m"
decimals={0} decimals={0}
deltaType="lowerIsBetter" deltaType="lowerIsBetter"
@@ -810,7 +839,6 @@ export function Characteristics() {
value="width" value="width"
/> />
<InfoWithDelta <InfoWithDelta
name="Height"
unit="m" unit="m"
decimals={0} decimals={0}
deltaType="lowerIsBetter" deltaType="lowerIsBetter"
@@ -818,7 +846,6 @@ export function Characteristics() {
value="height" value="height"
/> />
<InfoWithDelta <InfoWithDelta
name="Length"
unit="m" unit="m"
decimals={0} decimals={0}
deltaType="lowerIsBetter" deltaType="lowerIsBetter"
@@ -826,7 +853,6 @@ export function Characteristics() {
value="length" value="length"
/> />
<InfoWithDelta <InfoWithDelta
name="Volume"
unit="m" unit="m"
decimals={0} decimals={0}
deltaType="lowerIsBetter" deltaType="lowerIsBetter"