mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-23 19:49:50 +02:00
feat: optimize info lines
This commit is contained in:
1 parent
94cba0c9ba
commit
525b9377cc
1 file changed
+143
-140
+143
-140
@@ -1,7 +1,7 @@
|
|||||||
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 { clamp } from 'lodash-es';
|
import { clamp } from 'lodash-es';
|
||||||
import { useMemo, type ComponentProps, type ReactNode } from 'react';
|
import { memo, 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';
|
||||||
@@ -48,148 +48,151 @@ const [
|
|||||||
awaitableSkillDefinitions,
|
awaitableSkillDefinitions,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
export function InfoWithDelta({
|
export const InfoWithDelta = memo<InfoWithDeltaProps>(
|
||||||
stats,
|
({ stats, indent, noRanking, deltaType, ...props }) => {
|
||||||
indent,
|
const { strings } = useLocale();
|
||||||
noRanking,
|
const relativeAgainst = TankopediaEphemeral.use(
|
||||||
deltaType,
|
(state) => state.relativeAgainst,
|
||||||
...props
|
);
|
||||||
}: InfoWithDeltaProps) {
|
const uhWhatDoICallThisVariable =
|
||||||
const { strings } = useLocale();
|
|
||||||
const relativeAgainst = TankopediaEphemeral.use(
|
|
||||||
(state) => state.relativeAgainst,
|
|
||||||
);
|
|
||||||
const uhWhatDoICallThisVariable =
|
|
||||||
typeof props.value === 'function'
|
|
||||||
? props.value(stats)!
|
|
||||||
: (stats[props.value] as number);
|
|
||||||
const delta = useDelta(uhWhatDoICallThisVariable);
|
|
||||||
const protagonistTank = Duel.use((state) => state.protagonist.tank);
|
|
||||||
const shellIndex = Duel.use((state) =>
|
|
||||||
state.protagonist.gun.gun_type!.value.base.shells.indexOf(
|
|
||||||
state.protagonist.shell,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
const equipmentMatrix = Duel.use(
|
|
||||||
(state) => state.protagonist.equipmentMatrix,
|
|
||||||
);
|
|
||||||
const others = useMemo(() => {
|
|
||||||
const defaultSkills = createDefaultSkills(skillDefinitions);
|
|
||||||
|
|
||||||
return Object.values(tankDefinitions.tanks)
|
|
||||||
.filter(
|
|
||||||
(tank) =>
|
|
||||||
(relativeAgainst === TankopediaRelativeAgainst.Class &&
|
|
||||||
tank.tier === protagonistTank.tier &&
|
|
||||||
tank.class === protagonistTank.class) ||
|
|
||||||
(relativeAgainst === TankopediaRelativeAgainst.Tier &&
|
|
||||||
tank.tier === protagonistTank.tier) ||
|
|
||||||
relativeAgainst === TankopediaRelativeAgainst.All,
|
|
||||||
)
|
|
||||||
.map((tank) => {
|
|
||||||
const thisTankModel = modelDefinitions.models[tank.id];
|
|
||||||
const member = tankToDuelMember(
|
|
||||||
tank,
|
|
||||||
thisTankModel,
|
|
||||||
provisionDefinitions,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (member.gun.gun_type!.value.base.shells[shellIndex] === undefined) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
return tankCharacteristics(
|
|
||||||
{
|
|
||||||
applyDynamicArmor: false,
|
|
||||||
applyReactiveArmor: false,
|
|
||||||
applySpallLiner: false,
|
|
||||||
camouflage: member.camouflage,
|
|
||||||
consumables: member.consumables,
|
|
||||||
crewSkills: defaultSkills,
|
|
||||||
provisions: member.provisions,
|
|
||||||
engine: member.engine,
|
|
||||||
gun: member.gun,
|
|
||||||
equipmentMatrix: equipmentMatrix,
|
|
||||||
shell: member.gun.gun_type!.value.base.shells[shellIndex],
|
|
||||||
stockEngine: tank.engines[0],
|
|
||||||
stockGun: tank.turrets[0].guns[0],
|
|
||||||
stockTrack: tank.tracks[0],
|
|
||||||
stockTurret: tank.turrets[0],
|
|
||||||
tank,
|
|
||||||
track: member.track,
|
|
||||||
turret: member.turret,
|
|
||||||
assaultDistance: member.assaultDistance,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
equipmentDefinitions,
|
|
||||||
provisionDefinitions,
|
|
||||||
tankModelDefinition: modelDefinitions.models[tank.id],
|
|
||||||
},
|
|
||||||
);
|
|
||||||
})
|
|
||||||
.filter((tank) => {
|
|
||||||
if (tank === undefined) return false;
|
|
||||||
|
|
||||||
const othersValue =
|
|
||||||
typeof props.value === 'function'
|
|
||||||
? props.value(tank)!
|
|
||||||
: (tank[props.value] as number);
|
|
||||||
|
|
||||||
return othersValue !== undefined;
|
|
||||||
}) as TankCharacteristics[];
|
|
||||||
}, [relativeAgainst, shellIndex, equipmentMatrix]);
|
|
||||||
const betterTanks = others.filter((tank) => {
|
|
||||||
const othersValue =
|
|
||||||
typeof props.value === 'function'
|
typeof props.value === 'function'
|
||||||
? props.value(tank)!
|
? props.value(stats)!
|
||||||
: (tank[props.value] as number);
|
: (stats[props.value] as number);
|
||||||
|
const delta = useDelta(uhWhatDoICallThisVariable);
|
||||||
|
const protagonistTank = Duel.use((state) => state.protagonist.tank);
|
||||||
|
const shellIndex = Duel.use((state) =>
|
||||||
|
state.protagonist.gun.gun_type!.value.base.shells.indexOf(
|
||||||
|
state.protagonist.shell,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
const equipmentMatrix = Duel.use(
|
||||||
|
(state) => state.protagonist.equipmentMatrix,
|
||||||
|
);
|
||||||
|
const others = useMemo(() => {
|
||||||
|
const defaultSkills = createDefaultSkills(skillDefinitions);
|
||||||
|
|
||||||
if (othersValue === undefined) return false;
|
return Object.values(tankDefinitions.tanks)
|
||||||
return deltaType === 'lowerIsBetter'
|
.filter(
|
||||||
? othersValue < uhWhatDoICallThisVariable
|
(tank) =>
|
||||||
: othersValue > uhWhatDoICallThisVariable;
|
(relativeAgainst === TankopediaRelativeAgainst.Class &&
|
||||||
});
|
tank.tier === protagonistTank.tier &&
|
||||||
const goodness = (others.length - betterTanks.length) / others.length;
|
tank.class === protagonistTank.class) ||
|
||||||
let color: ComponentProps<typeof Progress>['color'];
|
(relativeAgainst === TankopediaRelativeAgainst.Tier &&
|
||||||
|
tank.tier === protagonistTank.tier) ||
|
||||||
|
relativeAgainst === TankopediaRelativeAgainst.All,
|
||||||
|
)
|
||||||
|
.map((tank) => {
|
||||||
|
const thisTankModel = modelDefinitions.models[tank.id];
|
||||||
|
const member = tankToDuelMember(
|
||||||
|
tank,
|
||||||
|
thisTankModel,
|
||||||
|
provisionDefinitions,
|
||||||
|
);
|
||||||
|
|
||||||
if (goodness <= 0.25) color = 'red';
|
if (
|
||||||
else if (goodness <= 0.5) color = 'orange';
|
member.gun.gun_type!.value.base.shells[shellIndex] === undefined
|
||||||
else if (goodness <= 0.75) color = 'yellow';
|
) {
|
||||||
else color = 'green';
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return tankCharacteristics(
|
||||||
<Flex direction="column">
|
{
|
||||||
<Info
|
applyDynamicArmor: false,
|
||||||
deltaType={deltaType}
|
applyReactiveArmor: false,
|
||||||
indent={indent}
|
applySpallLiner: false,
|
||||||
name={
|
camouflage: member.camouflage,
|
||||||
'name' in props
|
consumables: member.consumables,
|
||||||
? props.name
|
crewSkills: defaultSkills,
|
||||||
: strings.website.tools.tankopedia.characteristics.values[
|
provisions: member.provisions,
|
||||||
props.value
|
engine: member.engine,
|
||||||
]
|
gun: member.gun,
|
||||||
}
|
equipmentMatrix: equipmentMatrix,
|
||||||
delta={delta}
|
shell: member.gun.gun_type!.value.base.shells[shellIndex],
|
||||||
{...props}
|
stockEngine: tank.engines[0],
|
||||||
>
|
stockGun: tank.turrets[0].guns[0],
|
||||||
{uhWhatDoICallThisVariable}
|
stockTrack: tank.tracks[0],
|
||||||
</Info>
|
stockTurret: tank.turrets[0],
|
||||||
|
tank,
|
||||||
|
track: member.track,
|
||||||
|
turret: member.turret,
|
||||||
|
assaultDistance: member.assaultDistance,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
equipmentDefinitions,
|
||||||
|
provisionDefinitions,
|
||||||
|
tankModelDefinition: modelDefinitions.models[tank.id],
|
||||||
|
},
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.filter((tank) => {
|
||||||
|
if (tank === undefined) return false;
|
||||||
|
|
||||||
{!noRanking && (
|
const othersValue =
|
||||||
<Flex pl={indent ? '2' : '0'} align="center" gap="2">
|
typeof props.value === 'function'
|
||||||
<Progress
|
? props.value(tank)!
|
||||||
variant="soft"
|
: (tank[props.value] as number);
|
||||||
size="1"
|
|
||||||
value={goodness * 100}
|
|
||||||
color={color}
|
|
||||||
style={{ height: '0.125rem', opacity: 0.5 }}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Text color="gray" size="1">
|
return othersValue !== undefined;
|
||||||
{clamp(betterTanks.length + 1, 1, others.length)} / {others.length}
|
}) as TankCharacteristics[];
|
||||||
</Text>
|
}, [relativeAgainst, shellIndex, equipmentMatrix]);
|
||||||
</Flex>
|
const betterTanks = others.filter((tank) => {
|
||||||
)}
|
const othersValue =
|
||||||
</Flex>
|
typeof props.value === 'function'
|
||||||
);
|
? props.value(tank)!
|
||||||
}
|
: (tank[props.value] as number);
|
||||||
|
|
||||||
|
if (othersValue === undefined) return false;
|
||||||
|
return deltaType === 'lowerIsBetter'
|
||||||
|
? othersValue < uhWhatDoICallThisVariable
|
||||||
|
: othersValue > uhWhatDoICallThisVariable;
|
||||||
|
});
|
||||||
|
const goodness = (others.length - betterTanks.length) / others.length;
|
||||||
|
let color: ComponentProps<typeof Progress>['color'];
|
||||||
|
|
||||||
|
if (goodness <= 0.25) color = 'red';
|
||||||
|
else if (goodness <= 0.5) color = 'orange';
|
||||||
|
else if (goodness <= 0.75) color = 'yellow';
|
||||||
|
else color = 'green';
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Flex direction="column">
|
||||||
|
<Info
|
||||||
|
deltaType={deltaType}
|
||||||
|
indent={indent}
|
||||||
|
name={
|
||||||
|
'name' in props
|
||||||
|
? props.name
|
||||||
|
: strings.website.tools.tankopedia.characteristics.values[
|
||||||
|
props.value
|
||||||
|
]
|
||||||
|
}
|
||||||
|
delta={delta}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
{uhWhatDoICallThisVariable}
|
||||||
|
</Info>
|
||||||
|
|
||||||
|
{!noRanking && (
|
||||||
|
<Flex pl={indent ? '2' : '0'} align="center" gap="2">
|
||||||
|
<Progress
|
||||||
|
variant="soft"
|
||||||
|
size="1"
|
||||||
|
value={goodness * 100}
|
||||||
|
color={color}
|
||||||
|
style={{ height: '0.125rem', opacity: 0.5 }}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Text color="gray" size="1">
|
||||||
|
{clamp(betterTanks.length + 1, 1, others.length)} /{' '}
|
||||||
|
{others.length}
|
||||||
|
</Text>
|
||||||
|
</Flex>
|
||||||
|
)}
|
||||||
|
</Flex>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
(a, b) =>
|
||||||
|
(typeof a.value === 'function' ? a.value(a.stats) : a.stats[a.value]) ===
|
||||||
|
(typeof b.value === 'function' ? b.value(b.stats) : b.stats[b.value]),
|
||||||
|
);
|
||||||
Reference in new issue
Block a user