feat: implement most equalizer

This commit is contained in:
TrèsAbhi committed 2026-04-03 12:08:47 -05:00
1 parent 6835004945
commit 77c516a6eb
10 files changed
+58 -41

No files matched your search

+3
View File
@@ -168,6 +168,7 @@ if (changedTanks.length > 0) {
)
.map((id) => currentEquipmentDefinitions.equipments[id]);
const equalize = false;
const currentCharacteristics = tankCharacteristics(
{
tank: current,
@@ -193,6 +194,7 @@ if (changedTanks.length > 0) {
stockTurret: current.turrets[0],
track: currentTracks,
turret: currentTurret,
equalize,
},
{
equipmentDefinitions: currentEquipmentDefinitions,
@@ -225,6 +227,7 @@ if (changedTanks.length > 0) {
stockTurret: preview.turrets[0],
track: previewTracks,
turret: previewTurret,
equalize,
},
{
equipmentDefinitions: previewEquipmentDefinitions,
@@ -59,11 +59,12 @@ export const InfoWithDelta = memo<InfoWithDeltaProps>(
const delta = useDelta(uhWhatDoICallThisVariable);
const protagonistTank = Duel.use((state) => state.protagonist.tank);
const shellIndex = Duel.use((state) =>
state.protagonist.gun.shells.indexOf(state.protagonist.shell)
state.protagonist.gun.shells.indexOf(state.protagonist.shell),
);
const equipmentMatrix = Duel.use(
(state) => state.protagonist.equipmentMatrix
(state) => state.protagonist.equipmentMatrix,
);
const equalize = Duel.use((state) => state.equalize);
const others = useMemo(() => {
const defaultSkills = createDefaultSkills(skillDefinitions);
@@ -75,7 +76,7 @@ export const InfoWithDelta = memo<InfoWithDeltaProps>(
tank.class === protagonistTank.class) ||
(relativeAgainst === TankopediaRelativeAgainst.Tier &&
tank.tier === protagonistTank.tier) ||
relativeAgainst === TankopediaRelativeAgainst.All
relativeAgainst === TankopediaRelativeAgainst.All,
)
.map((tank) => {
const member = tankToDuelMember(tank, provisionDefinitions);
@@ -105,12 +106,13 @@ export const InfoWithDelta = memo<InfoWithDeltaProps>(
track: member.track,
turret: member.turret,
assaultDistance: member.assaultDistance,
equalize,
},
{
equipmentDefinitions,
provisionDefinitions,
tankModelDefinition: modelDefinitions.models[tank.id],
}
},
);
})
.filter((tank) => {
@@ -123,7 +125,7 @@ export const InfoWithDelta = memo<InfoWithDeltaProps>(
return othersValue !== undefined;
}) as TankCharacteristics[];
}, [relativeAgainst, shellIndex, equipmentMatrix]);
}, [relativeAgainst, shellIndex, equipmentMatrix, equalize]);
const betterTanks = others.filter((tank) => {
const othersValue =
typeof props.value === "function"
@@ -183,5 +185,5 @@ export const InfoWithDelta = memo<InfoWithDeltaProps>(
(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])
(typeof b.value === "function" ? b.value(b.stats) : b.stats[b.value]),
);
@@ -31,6 +31,7 @@ export function Characteristics({ skeleton }: MaybeSkeletonComponentProps) {
const equipmentMatrix = Duel.use(
(state) => state.protagonist.equipmentMatrix,
);
const equalize = Duel.use((state) => state.equalize);
const { tank, turret, gun, engine, track, shell } = Duel.use(
(state) => state.protagonist,
);
@@ -62,6 +63,7 @@ export function Characteristics({ skeleton }: MaybeSkeletonComponentProps) {
applyDynamicArmor: false,
applySpallLiner: false,
assaultDistance,
equalize,
},
{
tankModelDefinition,
@@ -16,7 +16,7 @@ import { ConfigurationChildWrapper } from "./ConfigurationChildWrapper";
export function Equalizer() {
const { strings } = useLocale();
const equalize = Duel.use((state) => state.protagonist.equalize);
const equalize = Duel.use((state) => state.equalize);
return (
<ConfigurationChildWrapper>
@@ -33,7 +33,7 @@ export function Equalizer() {
mt="2"
onClick={() => {
Duel.mutate((draft) => {
draft.protagonist.equalize = !draft.protagonist.equalize;
draft.equalize = !draft.equalize;
});
}}
width="100%"
@@ -47,6 +47,7 @@ export function tankCharacteristics(
applyDynamicArmor,
applySpallLiner,
assaultDistance,
equalize,
}: {
tank: TankDefinition;
turret: TurretDefinition;
@@ -67,6 +68,7 @@ export function tankCharacteristics(
applyDynamicArmor: boolean;
applySpallLiner: boolean;
assaultDistance: number;
equalize: boolean;
},
{
tankModelDefinition,
@@ -81,6 +83,13 @@ export function tankCharacteristics(
const preset = equipmentDefinitions.presets[tank.equipment_preset];
const turretModelDefinition = tankModelDefinition.turrets[turret.id];
const gunModelDefinition = turretModelDefinition.guns[gun.id];
const equalizer = (equalize ? tank.equalizer : undefined) ?? {
armor: 1,
damage: 1,
health: 1,
module_health: 1,
penetration: 1,
};
function equipment(id: number) {
return preset.slots.some((slot, index) => {
@@ -177,15 +186,17 @@ export function tankCharacteristics(
(coefficient([hasGunRammer, -0.05]) *
coefficient([true, degressiveStat(loaderMastery)])) /
coefficient([hasAdrenaline && gun.gun_type!.$case === "regular", 0.17]);
const penetrationCoefficient = coefficient([
hasCalibratedShells,
resolvePenetrationCoefficient(true, shell.type) - 1,
]);
const healthCoefficient = coefficient(
[hasSandbagArmor, 0.03],
[hasEnhancedSandbagArmor, 0.06],
[hasImprovedAssembly, 0.04],
);
const penetrationCoefficient =
coefficient([
hasCalibratedShells,
resolvePenetrationCoefficient(true, shell.type) - 1,
]) * equalizer.penetration;
const healthCoefficient =
coefficient(
[hasSandbagArmor, 0.03],
[hasEnhancedSandbagArmor, 0.06],
[hasImprovedAssembly, 0.04],
) * equalizer.health;
const shellVelocityCoefficient = coefficient(
[hasSupercharger, 0.35],
[hasImprovedGunPowder, 0.3],
@@ -345,7 +356,9 @@ export function tankCharacteristics(
const resolvedEnginePower = engine.power * enginePowerCoefficient;
const damageCoefficientWithoutAssault = armorDamageCoefficient;
const damageCoefficient =
damageCoefficientWithoutAssault * assaultDamageCoefficient;
damageCoefficientWithoutAssault *
assaultDamageCoefficient *
equalizer.damage;
const dpm = resolveDpm(
gun,
shell,
@@ -654,13 +667,3 @@ export const characteristicsOrder: {
items: ["crewCount"],
},
];
// export const characteristicsStyling: Record<
// TankCharacteristicsKey,
// {
// name: string;
// indent?: boolean;
// condition?: TankCharacteristicsCondition[];
// }
// > = {
// };
@@ -26,6 +26,5 @@ export function tankToDuelMember(
track: tank.tracks.at(-1)!,
turret,
assaultDistance: (gun.assault_ranges?.ranges[0].distance ?? 0) / 2,
equalize: false,
} satisfies DuelMember;
}
@@ -45,6 +45,7 @@ export function Page({ locale }: LocaleAcceptorProps) {
function Content() {
const members = CompareEphemeral.use((state) => state.members);
const equalize = CompareEphemeral.use((state) => state.equalize);
const [addTankDialogOpen, setAddTankDialogOpen] = useState(false);
const crewSkills = CompareEphemeral.use((state) => state.crewSkills);
const { strings } = useLocale();
@@ -61,26 +62,30 @@ function Content() {
stockTurret: thisMember.tank.turrets[0],
applyReactiveArmor: members.some(
(member) =>
member.key !== thisMember.key && member.consumables.includes(33)
member.key !== thisMember.key &&
member.consumables.includes(33),
),
applyDynamicArmor: members.some(
(member) =>
member.key !== thisMember.key && member.consumables.includes(73)
member.key !== thisMember.key &&
member.consumables.includes(73),
),
applySpallLiner: members.some(
(member) =>
member.key !== thisMember.key && member.provisions.includes(101)
member.key !== thisMember.key &&
member.provisions.includes(101),
),
assaultDistance: thisMember.assaultDistance,
equalize,
},
{
equipmentDefinitions: equipmentDefinitions,
provisionDefinitions: provisionDefinitions,
tankModelDefinition: modelDefinitions.models[thisMember.tank.id],
}
)
},
),
),
[members, crewSkills]
[members, crewSkills],
);
useEffect(() => {
@@ -112,7 +117,7 @@ function Content() {
window.history.replaceState(
{},
"",
`${window.location.pathname}?${search.toString()}`
`${window.location.pathname}?${search.toString()}`,
);
}, [members]);
@@ -33,7 +33,7 @@ export const getStaticPaths = (async () => {
parentPaths.map((parent) => ({
params: { ...parent.params, slug: tank.slug },
props: { ...parent.props, id: tank.id },
}))
})),
)
.flat();
}) satisfies GetStaticPaths;
@@ -86,8 +86,9 @@ const characteristics = tankCharacteristics(
stockTrack: tank.tracks[0],
track: tank.tracks.at(-1)!,
assaultDistance: 0,
equalize: false,
},
{ equipmentDefinitions, provisionDefinitions, tankModelDefinition }
{ equipmentDefinitions, provisionDefinitions, tankModelDefinition },
);
const description = literals(
strings.website.tools.tankopedia.tank_seo_description,
@@ -98,7 +99,7 @@ const description = literals(
penetration: Math.round(characteristics.penetration).toLocaleString(locale),
speed: Math.round(characteristics.speedForwards).toLocaleString(locale),
health: Math.round(characteristics.health).toLocaleString(locale),
}
},
);
const guideUrl = `${assertSecret(import.meta.env.PUBLIC_GUIDE_WEBSITE)}/${tank.slug}`;
@@ -7,6 +7,7 @@ export interface CompareMember extends DuelMember {
export interface CompareEphemeral {
crewSkills: Record<string, number>;
equalize: boolean;
members: CompareMember[];
sorting?: {
direction: "ascending" | "descending";
@@ -19,5 +20,6 @@ export const CompareEphemeral = new Varuna<
Record<string, number>
>((crewSkills) => ({
crewSkills,
equalize: false,
members: [],
}));
+2 -2
View File
@@ -36,12 +36,12 @@ export interface DuelMember {
camouflage: boolean;
cooldownBooster: number;
assaultDistance: number;
equalize: boolean;
}
export interface DuelStore {
protagonist: DuelMember;
antagonist: DuelMember;
equalize: boolean;
}
const provisionDefinitions = await awaitableProvisionDefinitions;
@@ -52,5 +52,5 @@ export const Duel = new Varuna<
>(({ tank, model }) => {
const protagonist = tankToDuelMember(tank, provisionDefinitions);
return { protagonist, antagonist: protagonist, model };
return { protagonist, antagonist: protagonist, model, equalize: false };
});