feat: characteristics

Co-authored-by: Copilot <[email protected]>
This commit is contained in:
TrèsAbhiandCopilot committed 2026-04-28 22:31:28 -05:00
1 parent 7767481633
commit 249f62759e
3 files changed
+204 -61

No files matched your search

@@ -20,7 +20,6 @@ type Characteristic = (helpers: {
state: TankState; state: TankState;
tank: Tank; tank: Tank;
parameters: StageParameters; parameters: StageParameters;
id: string;
}) => CharacteristicOutput; }) => CharacteristicOutput;
export type CharacteristicName = keyof typeof characteristics; export type CharacteristicName = keyof typeof characteristics;
@@ -409,8 +408,8 @@ export const characteristics = {
return tank.tank!.tank_type; return tank.tank!.tank_type;
}, },
id({ id }) { id({ state }) {
return id; return state.id;
}, },
slug({ tank }) { slug({ tank }) {
@@ -3,7 +3,7 @@ import {
ShellUpgradeSingleChange_AttributeName, ShellUpgradeSingleChange_AttributeName,
TankAttributeChange_AttributeName, TankAttributeChange_AttributeName,
} from "@protos/game/proto/legacy/blitz_static_tank_upgrade_single_stage"; } from "@protos/game/proto/legacy/blitz_static_tank_upgrade_single_stage";
import { aggregateStageParameters } from "./aggregateParameters"; import { aggregateParameters } from "./aggregateParameters";
import { import {
characteristics, characteristics,
type CharacteristicName, type CharacteristicName,
@@ -16,15 +16,8 @@ export type ComputedCharacteristics = Record<
CharacteristicOutput CharacteristicOutput
>; >;
export function computeCharacteristics( export function computeCharacteristics(tank: Tank, state: TankState) {
id: string, const parameters = aggregateParameters(tank.tank!, state.upgrades);
tank: Tank,
state: TankState,
) {
const parameters = aggregateStageParameters(
tank.tank!.base_stats!,
tank.tank!.upgrade_stages.slice(0, state.stage),
);
const computed: Partial<ComputedCharacteristics> = {}; const computed: Partial<ComputedCharacteristics> = {};
@@ -94,7 +87,6 @@ export function computeCharacteristics(
state, state,
tank, tank,
parameters, parameters,
id,
}); });
computed[name] = value; computed[name] = value;
} }
@@ -1,12 +1,8 @@
import { Grade } from "@blitzkit/closed/protos/game/proto/legacy/blitz_static_standard_grades_enum"; import { Grade } from "@blitzkit/closed/protos/game/proto/legacy/blitz_static_standard_grades_enum";
import { PenetrationGroup_CommonData } from "@blitzkit/closed/protos/game/proto/legacy/blitz_static_tank_penetration_group"; import { StageParameters_StageType } from "@blitzkit/closed/protos/game/proto/legacy/blitz_static_tank_upgrade_single_stage";
import { import { useMemo } from "react";
PenetrationGroupUpgrade_TankPart,
StageParameters_StageType,
TankAttributeChange_AttributeName,
} from "@blitzkit/closed/protos/game/proto/legacy/blitz_static_tank_upgrade_single_stage";
import { api } from "../../../../core/api/dynamic"; import { api } from "../../../../core/api/dynamic";
import { aggregateParameters } from "../../../../core/tankopedia/aggregateParameters"; import { computeCharacteristics } from "../../../../core/tankopedia/computeCharacteristics";
import { useAwait } from "../../../../hooks/useAwait"; import { useAwait } from "../../../../hooks/useAwait";
import { useGameStrings } from "../../../../hooks/useGameStrings"; import { useGameStrings } from "../../../../hooks/useGameStrings";
import { LocaleProvider } from "../../../../hooks/useLocale"; import { LocaleProvider } from "../../../../hooks/useLocale";
@@ -38,9 +34,9 @@ function Content() {
`tank-${protagonist.id}`, `tank-${protagonist.id}`,
); );
const parameters = aggregateParameters( const { characteristics } = useMemo(
protagonistTank.tank!, () => computeCharacteristics(protagonistTank, protagonist),
protagonist.upgrades, [protagonist],
); );
return ( return (
@@ -148,44 +144,200 @@ function Content() {
); );
})} })}
<h2>parameters</h2> <h2>characteristics</h2>
<h3>attributes</h3> {Object.entries(characteristics).map(([key, value]) => (
<p>
{parameters.attributes.map((attribute) => { {key}: {value}
return ( </p>
<span> ))}
{TankAttributeChange_AttributeName[attribute.attribute_name]}:{" "}
{attribute.value}
</span>
);
})}
<h3>penetration groups</h3>
{parameters.penetration_groups_upgrades.map((upgrade) => {
return (
<>
<h4>{PenetrationGroupUpgrade_TankPart[upgrade.tank_part]}</h4>
<span>
primary armor ({upgrade.primary_armor.length}):{" "}
{upgrade.primary_armor}
</span>
<br />
{upgrade.penetration_groups.map((group) => {
return (
<span>
{group.group_name}: {group.armor} (
{PenetrationGroup_CommonData[group.common_data]})
</span>
);
})}
</>
);
})}
</> </>
); );
// const parameters = aggregateParameters(
// protagonistTank.tank!,
// protagonist.upgrades,
// );
// if (parameters.modules_upgrades.length > 0) {
// throw new Error("Modules upgrades display not implemented");
// }
// return (
// <>
// <h1>{protagonist.id}</h1>
// <br />
// <h2>upgrades</h2>
// {protagonistTank.tank!.upgrade_lines.map((line) => {
// return (
// <>
// <h3>
// {line.name} ({protagonist.upgrades[line.name]})
// </h3>
// <div
// style={{
// display: "flex",
// flexDirection: "column",
// alignItems: "flex-start",
// gap: 8,
// }}
// >
// {line.stages.map((stage, index) => {
// if (stage.custom_picture) {
// throw new Error("Custom picture not supported");
// }
// return (
// <button
// key={stage.tech_name}
// onClick={() => {
// Tankopedia.mutate((draft) => {
// draft.protagonist.upgrades[line.name] = index;
// for (const required of stage.required_upgrades) {
// for (const line of protagonistTank.tank!
// .upgrade_lines) {
// let i = 0;
// for (const stage of line.stages) {
// if (stage.tech_name === required) {
// draft.protagonist.upgrades[line.name] =
// Math.max(
// draft.protagonist.upgrades[line.name],
// i,
// );
// }
// i++;
// }
// }
// }
// for (const line of protagonistTank.tank!
// .upgrade_lines) {
// let i = draft.protagonist.upgrades[line.name];
// while (i > 0) {
// const currentStage = line.stages[i];
// const valid = currentStage.required_upgrades.every(
// (required) => {
// for (const line of protagonistTank.tank!
// .upgrade_lines) {
// const idx =
// draft.protagonist.upgrades[line.name];
// if (
// line.stages[idx]?.tech_name === required
// ) {
// return true;
// }
// }
// return false;
// },
// );
// if (valid) break;
// i--;
// }
// draft.protagonist.upgrades[line.name] = i;
// }
// });
// }}
// style={{
// backgroundColor:
// protagonist.upgrades[line.name] === index
// ? "green"
// : undefined,
// }}
// >
// {stage.tech_name}: {Grade[stage.grade]}
// {StageParameters_StageType[stage.stage_type]}
// {tankEntityGameStrings[stage.display_name]}
// </button>
// );
// })}
// </div>
// </>
// );
// })}
// <h2>characteristics</h2>
// {}
// <h2>parameters</h2>
// <h3>attributes</h3>
// {parameters.attributes.map((attribute) => {
// return (
// <span>
// {TankAttributeChange_AttributeName[attribute.attribute_name]}:{" "}
// {attribute.value}
// </span>
// );
// })}
// <h3>penetration groups</h3>
// {parameters.penetration_groups_upgrades.map((upgrade) => {
// return (
// <>
// <h4>{PenetrationGroupUpgrade_TankPart[upgrade.tank_part]}</h4>
// <span>
// primary armor ({upgrade.primary_armor.length}):{" "}
// {upgrade.primary_armor}
// </span>
// <br />
// {upgrade.penetration_groups.map((group) => {
// return (
// <span>
// {group.group_name}: {group.armor} (
// {PenetrationGroup_CommonData[group.common_data]})
// </span>
// );
// })}
// </>
// );
// })}
// <h2>modules ({parameters.modules_upgrades.length})</h2>
// {parameters.modules_upgrades.map((upgrade) => {
// return (
// <span>{ModuleUpgrade_AttributeName[upgrade.attribute_name]}</span>
// );
// })}
// <h2>shells</h2>
// {parameters.shells_upgrades.map((upgrade) => {
// return (
// <>
// <h3>
// {upgrade.shell_id}: {ShellUpgrade_ShellType[upgrade.shell_type]}
// </h3>
// <pre>
// silver_price: {JSON.stringify(upgrade.silver_price, null, 2)}
// </pre>
// <pre>
// tray_shells: {JSON.stringify(upgrade.tray_shells, null, 2)}
// </pre>
// </>
// );
// })}
// </>
// );
} }