From af85fb74cb41a218311ffc194298eae4302292d7 Mon Sep 17 00:00:00 2001
From: tresabhi <43380238+tresabhi@users.noreply.github.com>
Date: Thu, 1 Oct 2026 15:52:14 -0500
Subject: [PATCH] haha characteristics render!
---
.../TankopediaCharacteristics/index.tsx | 8 +--
.../website/src/config/characteristics.ts | 6 +-
.../website/src/hooks/useCharacteristics.ts | 72 +++++++++++++++++++
packages/website/src/layouts/BaseLayout.astro | 8 +--
.../[...locale]/tanks/[slug]/_index.tsx | 10 +--
packages/website/src/stores/tankopedia.ts | 10 ++-
.../src/tankopedia/computeCharacteristics.ts | 7 --
.../website/src/tankopedia/createTankState.ts | 5 +-
packages/website/src/tankopedia/tankState.ts | 1 -
packages/website/src/types/characteristics.ts | 25 ++++---
10 files changed, 114 insertions(+), 38 deletions(-)
create mode 100644 packages/website/src/hooks/useCharacteristics.ts
delete mode 100644 packages/website/src/tankopedia/computeCharacteristics.ts
diff --git a/packages/website/src/components/TankopediaCharacteristics/index.tsx b/packages/website/src/components/TankopediaCharacteristics/index.tsx
index 7fb72acfc..f79154dfa 100644
--- a/packages/website/src/components/TankopediaCharacteristics/index.tsx
+++ b/packages/website/src/components/TankopediaCharacteristics/index.tsx
@@ -23,7 +23,7 @@ export function TankopediaCharacteristics({
{characteristicsGroups.map((group) => {
const items = group.order.filter(
- (item) => "name" in item && item.name in characteristics,
+ (item) => "name" in item && characteristics.has(item.name),
).length;
const shouldRender = items > 0;
@@ -51,7 +51,7 @@ function Group({ group, characteristics }: GroupProps) {
const strings = useStrings();
const toys = group.order.filter((item) => "toy" in item).length;
const items = group.order.filter(
- (item) => "name" in item && characteristics[item.name] !== null,
+ (item) => "name" in item && characteristics.has(item.name),
).length;
const groupSpan = `calc(${toys} * var(--group-span) + ${items} + 2)`;
const contentSpan = `calc(${toys} * var(--group-span) + ${items})`;
@@ -88,8 +88,8 @@ function Group({ group, characteristics }: GroupProps) {
{group.order.map((item) => (
<>
{"toy" in item &&
}
- {"name" in item && characteristics[item.name] !== null && (
-
+ {"name" in item && characteristics.get(item.name) && (
+
)}
>
))}
diff --git a/packages/website/src/config/characteristics.ts b/packages/website/src/config/characteristics.ts
index e8eb14731..9621aaf19 100644
--- a/packages/website/src/config/characteristics.ts
+++ b/packages/website/src/config/characteristics.ts
@@ -26,12 +26,12 @@ export const characteristics = {
damage: {
type: CharacteristicType.Number,
- compute({ characteristic, gun, shell, equalizer, assault_distance }) {
+ compute({ characteristic, gun, shell, environment }) {
let coefficient = 1;
if (gun.assault_ranges && gun.assault_ranges.types.includes(shell.type)) {
const match = gun.assault_ranges.ranges.find(
- ({ distance }) => distance >= assault_distance,
+ ({ distance }) => distance >= environment.assault_distance,
);
if (match !== undefined) {
@@ -39,7 +39,7 @@ export const characteristics = {
}
}
- coefficient *= equalizer.damage;
+ // coefficient *= equalizer.damage;
return coefficient * shell.armor_damage;
},
diff --git a/packages/website/src/hooks/useCharacteristics.ts b/packages/website/src/hooks/useCharacteristics.ts
new file mode 100644
index 000000000..bb088c60d
--- /dev/null
+++ b/packages/website/src/hooks/useCharacteristics.ts
@@ -0,0 +1,72 @@
+import { api } from "../api/dynamic";
+import { characteristics } from "../config/characteristics";
+import { Tankopedia, type TankEnvironment } from "../stores/tankopedia";
+import type { TankState } from "../tankopedia/tankState";
+import type {
+ CharacteristicContext,
+ CharacteristicName,
+ ComputedCharacteristics,
+} from "../types/characteristics";
+import type { DuelSide } from "./useEquipment";
+
+const tanks = await api.tanks();
+
+export function useCharacteristics(side: DuelSide) {
+ const state = Tankopedia.use((state) => state[side]);
+ const environment = Tankopedia.use((state) => state.environment);
+
+ return computeCharacteristics(state, environment);
+}
+
+export function computeCharacteristics(
+ state: TankState,
+ environment: TankEnvironment,
+) {
+ const computed: ComputedCharacteristics = new Map();
+
+ const tank = tanks.tanks[state.tank];
+ const engine = tank.engines.find((engine) => engine.id === state.engine)!;
+ const track = tank.tracks.find((track) => track.id === state.track)!;
+ const turret = tank.turrets.find((turret) => turret.id === state.turret)!;
+ const gun = turret.guns.find((gun) => gun.id === state.gun)!;
+ const shell = gun.shells.find((shell) => shell.id === state.shell)!;
+
+ function characteristic(name: CharacteristicName) {
+ if (!computed.has(name)) {
+ throw new Error(`Characteristic ${name} not computed yet`);
+ }
+
+ return computed.get(name)!;
+ }
+
+ const context = {
+ state,
+ environment,
+
+ tank,
+ engine,
+ track,
+ turret,
+ gun,
+ shell,
+
+ characteristic,
+ } satisfies CharacteristicContext;
+
+ for (const name in characteristics) {
+ const characteristic = characteristics[name as CharacteristicName];
+ let shouldRender = true;
+
+ if ("should_render" in characteristic) {
+ shouldRender = characteristic.should_render(context);
+ }
+
+ if (!shouldRender) continue;
+
+ const value = characteristic.compute(context);
+
+ computed.set(name as CharacteristicName, value);
+ }
+
+ return computed;
+}
diff --git a/packages/website/src/layouts/BaseLayout.astro b/packages/website/src/layouts/BaseLayout.astro
index b51471d43..1b6b56dfb 100644
--- a/packages/website/src/layouts/BaseLayout.astro
+++ b/packages/website/src/layouts/BaseLayout.astro
@@ -43,14 +43,14 @@ const { accent, locale } = Astro.props;
color: var(--gray-12);
font-family: var(--font-family-regular);
- .app {
+ main {
display: flex;
flex: 1;
flex-direction: column;
background-color: var(--gray-1);
- padding: var(--space-4);
+ /* padding: var(--space-4); */
gap: var(--space-6);
}
}
@@ -75,9 +75,9 @@ const { accent, locale } = Astro.props;
-
+
-
+
diff --git a/packages/website/src/pages/[...chunk_default]/[...locale]/tanks/[slug]/_index.tsx b/packages/website/src/pages/[...chunk_default]/[...locale]/tanks/[slug]/_index.tsx
index a13ada0e9..1bd4c01da 100644
--- a/packages/website/src/pages/[...chunk_default]/[...locale]/tanks/[slug]/_index.tsx
+++ b/packages/website/src/pages/[...chunk_default]/[...locale]/tanks/[slug]/_index.tsx
@@ -8,8 +8,8 @@ import { defaultEqualizer } from "../../../../../config/equalizer";
import { withErrorWrapper } from "../../../../../hocs/withErrorWrapper";
import { withLocale } from "../../../../../hocs/withLocale";
import { useAwait } from "../../../../../hooks/useAwait";
+import { useCharacteristics } from "../../../../../hooks/useCharacteristics";
import { Tankopedia } from "../../../../../stores/tankopedia";
-import { computeCharacteristics } from "../../../../../tankopedia/computeCharacteristics";
import type { MaybeSkeletonComponentProps } from "../../../../../types/maybeSkeletonComponentProps";
import styles from "./_index.module.css";
@@ -26,14 +26,10 @@ export const Page = withErrorWrapper(
Tankopedia.useInitialization(protagonistTank);
const protagonist = Tankopedia.use((state) => state.protagonist);
- // const protagonistEquipment = useEquipment("protagonist", protagonistTank.tank!);
+ const equalize = Tankopedia.use((state) => state.environment.equalize);
- const characteristics = useMemo(
- () => computeCharacteristics(),
- [protagonist],
- );
+ const characteristics = useCharacteristics("protagonist");
- const equalize = Tankopedia.use((state) => state.equalize);
const thicknessRange = useMemo(() => {
const entries = Object.values(tanks.tanks);
const filtered = entries.filter(
diff --git a/packages/website/src/stores/tankopedia.ts b/packages/website/src/stores/tankopedia.ts
index 01c2015b6..58afd9a56 100644
--- a/packages/website/src/stores/tankopedia.ts
+++ b/packages/website/src/stores/tankopedia.ts
@@ -75,14 +75,18 @@ export enum TankopediaRelativeAgainst {
All,
}
+export interface TankEnvironment {
+ equalize: boolean;
+ assault_distance: number;
+}
+
interface Tankopedia {
disturbed: boolean;
revealed: boolean;
protagonist: TankState;
antagonist: TankState;
-
- equalize: boolean;
+ environment: TankEnvironment;
shot?: Shot;
skills: Record
;
@@ -121,7 +125,7 @@ export const Tankopedia = new Soapstone(
antagonist: createTankState(tank),
model: models.models[tank.id],
- equalize: false,
+ environment: { equalize: false, assault_distance: 0 },
relativeAgainst: TankopediaRelativeAgainst.Class,
editStatic: false,
diff --git a/packages/website/src/tankopedia/computeCharacteristics.ts b/packages/website/src/tankopedia/computeCharacteristics.ts
deleted file mode 100644
index ed53640b2..000000000
--- a/packages/website/src/tankopedia/computeCharacteristics.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-import type { ComputedCharacteristics } from "../types/characteristics";
-
-export function computeCharacteristics() {
- const characteristics: Partial = {};
-
- return characteristics as ComputedCharacteristics;
-}
diff --git a/packages/website/src/tankopedia/createTankState.ts b/packages/website/src/tankopedia/createTankState.ts
index eaed6b008..967d2fbdf 100644
--- a/packages/website/src/tankopedia/createTankState.ts
+++ b/packages/website/src/tankopedia/createTankState.ts
@@ -27,7 +27,10 @@ export function createTankState(tank: TankDefinition) {
shell: gun.shells[0].id,
track: tank.tracks.at(-1)!.id,
- assault_distance: (gun.assault_ranges?.ranges[0].distance ?? 0) / 2,
+ environment: {
+ assault_distance: (gun.assault_ranges?.ranges[0].distance ?? 0) / 2,
+ },
+
speed: 0,
equipment: {},
diff --git a/packages/website/src/tankopedia/tankState.ts b/packages/website/src/tankopedia/tankState.ts
index 8ac07265b..e3e8e008d 100644
--- a/packages/website/src/tankopedia/tankState.ts
+++ b/packages/website/src/tankopedia/tankState.ts
@@ -9,7 +9,6 @@ export interface TankState {
shell: number;
track: number;
- assault_distance: number;
speed: number;
equipment: Record;
diff --git a/packages/website/src/types/characteristics.ts b/packages/website/src/types/characteristics.ts
index c82c432ba..4dbf6c0d0 100644
--- a/packages/website/src/types/characteristics.ts
+++ b/packages/website/src/types/characteristics.ts
@@ -1,11 +1,16 @@
import type { Strings } from "@blitzkit/i18n";
import type {
- Equalizer,
+ EngineDefinition,
GunDefinition,
ShellDefinition,
+ TankDefinition,
+ TrackDefinition,
+ TurretDefinition,
} from "@blitzkit/protos";
import type { ReactNode } from "react";
import { characteristics } from "../config/characteristics";
+import type { TankEnvironment } from "../stores/tankopedia";
+import type { TankState } from "../tankopedia/tankState";
export type Characteristic = {
should_render?(context: CharacteristicContext): boolean;
@@ -20,14 +25,17 @@ export type Characteristic = {
}
);
-interface CharacteristicContext {
+export interface CharacteristicContext {
+ state: TankState;
+ environment: TankEnvironment;
+
+ tank: TankDefinition;
+ engine: EngineDefinition;
+ track: TrackDefinition;
+ turret: TurretDefinition;
gun: GunDefinition;
shell: ShellDefinition;
- equalizer: Equalizer;
-
- assault_distance: number;
-
characteristic(
name: CharacteristicName,
): ReturnType;
@@ -41,8 +49,9 @@ export enum CharacteristicType {
export type CharacteristicName = keyof typeof characteristics;
export type CharacteristicReturnType = ReturnType;
-export type ComputedCharacteristics = Partial<
- Record
+export type ComputedCharacteristics = Map<
+ CharacteristicName,
+ CharacteristicReturnType
>;
export interface CharacteristicRenderConfig {