mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-22 19:19:52 +02:00
feat: some stats
This commit is contained in:
1 parent
bd412cdaa2
commit
f696c5f3c9
15 files changed
+192
-123
No files matched your search
@@ -2,31 +2,63 @@
|
||||
|
||||
import { PlusIcon } from '@radix-ui/react-icons';
|
||||
import { Button, Dialog, Flex, Table, Text } from '@radix-ui/themes';
|
||||
import { usePathname, useRouter, useSearchParams } from 'next/navigation';
|
||||
import { use, useCallback, useState } from 'react';
|
||||
import { useSearchParams } from 'next/navigation';
|
||||
import { use, useState } from 'react';
|
||||
import PageWrapper from '../../../components/PageWrapper';
|
||||
import { tankDefinitions } from '../../../core/blitzkrieg/tankDefinitions';
|
||||
import { tankCharacteristics } from '../../../core/blitzkrieg/tankCharacteristics';
|
||||
import { tankIcon } from '../../../core/blitzkrieg/tankIcon';
|
||||
import mutateCompare, { useCompare } from '../../../stores/compare';
|
||||
import { genericDefaultEquipmentMatrix } from '../../../stores/duel/constants';
|
||||
import { TankSearch } from '../tankopedia/components/TankSearch';
|
||||
|
||||
export default function Page() {
|
||||
const router = useRouter();
|
||||
const pathname = usePathname();
|
||||
const searchParams = useSearchParams();
|
||||
const tanks = searchParams.get('tanks')?.split(',').map(Number) ?? [];
|
||||
const awaitedTankDefinitions = use(tankDefinitions);
|
||||
const tanks = useCompare((state) => state.tanks);
|
||||
const [addTankDialogOpen, setAddTankDialogOpen] = useState(false);
|
||||
|
||||
const createQueryString = useCallback(
|
||||
(name: string, value: string) => {
|
||||
const params = new URLSearchParams(searchParams.toString());
|
||||
params.set(name, value);
|
||||
|
||||
return params.toString();
|
||||
},
|
||||
[searchParams],
|
||||
const stats = use(
|
||||
Promise.all(
|
||||
tanks.map((item) =>
|
||||
tankCharacteristics({
|
||||
...item,
|
||||
stockEngine: item.tank.engines[0],
|
||||
stockGun: item.tank.turrets[0].guns[0],
|
||||
stockTrack: item.tank.tracks[0],
|
||||
stockTurret: item.tank.turrets[0],
|
||||
}),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
function Row({
|
||||
value,
|
||||
decimals,
|
||||
name,
|
||||
}: {
|
||||
name: string;
|
||||
value: (member: Awaited<ReturnType<typeof tankCharacteristics>>) => number;
|
||||
decimals?: number;
|
||||
}) {
|
||||
const values = stats.map(value);
|
||||
|
||||
return (
|
||||
<Table.Row>
|
||||
<Table.RowHeaderCell>{name}</Table.RowHeaderCell>
|
||||
|
||||
{values.map((value, index) => (
|
||||
<Table.Cell key={index}>
|
||||
<Text
|
||||
color={
|
||||
index === 0 ? undefined : value > values[0] ? 'green' : 'red'
|
||||
}
|
||||
>
|
||||
{decimals === undefined ? value : value.toFixed(decimals)}
|
||||
</Text>
|
||||
</Table.Cell>
|
||||
))}
|
||||
</Table.Row>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<PageWrapper color="crimson" size="100%">
|
||||
<Flex justify="center">
|
||||
@@ -51,12 +83,26 @@ export default function Page() {
|
||||
<TankSearch
|
||||
compact
|
||||
onSelect={(tank) => {
|
||||
tanks.push(tank.id);
|
||||
router.push(
|
||||
pathname +
|
||||
'?' +
|
||||
createQueryString('tanks', tanks.join(',')),
|
||||
);
|
||||
mutateCompare((draft) => {
|
||||
draft.tanks.push({
|
||||
camouflage: true,
|
||||
consumables: [],
|
||||
equipmentMatrix: genericDefaultEquipmentMatrix,
|
||||
cooldownBooster: 0,
|
||||
crewMastery: 1,
|
||||
provisions: [],
|
||||
engine: tank.engines.at(-1)!,
|
||||
gun: tank.turrets.at(-1)!.guns.at(-1)!,
|
||||
shell: tank.turrets.at(-1)!.guns.at(-1)!.shells[0],
|
||||
tank,
|
||||
track: tank.tracks.at(-1)!,
|
||||
yaw: 0,
|
||||
pitch: 0,
|
||||
turret: tank.turrets.at(-1)!,
|
||||
crewSkills: {},
|
||||
});
|
||||
});
|
||||
|
||||
setAddTankDialogOpen(false);
|
||||
}}
|
||||
/>
|
||||
@@ -76,30 +122,21 @@ export default function Page() {
|
||||
>
|
||||
<Table.Header>
|
||||
<Table.Row>
|
||||
<Table.ColumnHeaderCell width="0">
|
||||
<Flex
|
||||
align="center"
|
||||
justify="center"
|
||||
style={{ width: '100%', height: '100%' }}
|
||||
>
|
||||
Statistics
|
||||
</Flex>
|
||||
</Table.ColumnHeaderCell>
|
||||
{tanks.map((id) => {
|
||||
const tank = awaitedTankDefinitions[id];
|
||||
<Table.ColumnHeaderCell />
|
||||
|
||||
{tanks.map(({ tank }) => {
|
||||
return (
|
||||
<Table.ColumnHeaderCell width="0">
|
||||
<Table.ColumnHeaderCell width="0" key={tank.id}>
|
||||
<Flex direction="column" align="center">
|
||||
<img
|
||||
src={tankIcon(id)}
|
||||
src={tankIcon(tank.id)}
|
||||
width={64}
|
||||
height={64}
|
||||
style={{
|
||||
objectFit: 'contain',
|
||||
}}
|
||||
/>
|
||||
<Text>{tank.name}</Text>
|
||||
<Text style={{ textAlign: 'center' }}>{tank.name}</Text>
|
||||
</Flex>
|
||||
</Table.ColumnHeaderCell>
|
||||
);
|
||||
@@ -108,23 +145,7 @@ export default function Page() {
|
||||
</Table.Header>
|
||||
|
||||
<Table.Body>
|
||||
<Table.Row>
|
||||
<Table.RowHeaderCell>Stat 1</Table.RowHeaderCell>
|
||||
{tanks.map((id) => {
|
||||
const tank = awaitedTankDefinitions[id];
|
||||
|
||||
return <Table.Cell>{Math.random()}</Table.Cell>;
|
||||
})}
|
||||
</Table.Row>
|
||||
|
||||
<Table.Row>
|
||||
<Table.RowHeaderCell>Stat 2</Table.RowHeaderCell>
|
||||
{tanks.map((id) => {
|
||||
const tank = awaitedTankDefinitions[id];
|
||||
|
||||
return <Table.Cell>{Math.random()}</Table.Cell>;
|
||||
})}
|
||||
</Table.Row>
|
||||
<Row name="DPM" value={(stats) => stats.dpm} decimals={0} />
|
||||
</Table.Body>
|
||||
</Table.Root>
|
||||
</Flex>
|
||||
|
||||
@@ -10,7 +10,9 @@ export function Equipment() {
|
||||
const awaitedEquipmentDefinitions = use(equipmentDefinitions);
|
||||
const equipmentRows =
|
||||
awaitedEquipmentDefinitions.presets[protagonist.tank.equipment];
|
||||
const equipmentMatrix = useDuel((state) => state.protagonist!.equipment);
|
||||
const equipmentMatrix = useDuel(
|
||||
(state) => state.protagonist!.equipmentMatrix,
|
||||
);
|
||||
|
||||
return (
|
||||
<ConfigurationChildWrapper>
|
||||
@@ -21,7 +23,7 @@ export function Equipment() {
|
||||
color="red"
|
||||
onClick={() => {
|
||||
mutateDuel((draft) => {
|
||||
draft.protagonist!.equipment.forEach((row) => {
|
||||
draft.protagonist!.equipmentMatrix.forEach((row) => {
|
||||
row.forEach((_, index) => {
|
||||
row[index] = 0;
|
||||
});
|
||||
@@ -46,10 +48,13 @@ export function Equipment() {
|
||||
onClick={() => {
|
||||
mutateDuel((draft) => {
|
||||
if (equipmentMatrix[rowIndex][columnIndex] === -1) {
|
||||
draft.protagonist!.equipment[rowIndex][columnIndex] = 0;
|
||||
draft.protagonist!.equipmentMatrix[rowIndex][
|
||||
columnIndex
|
||||
] = 0;
|
||||
} else {
|
||||
draft.protagonist!.equipment[rowIndex][columnIndex] =
|
||||
-1;
|
||||
draft.protagonist!.equipmentMatrix[rowIndex][
|
||||
columnIndex
|
||||
] = -1;
|
||||
}
|
||||
});
|
||||
}}
|
||||
@@ -62,9 +67,13 @@ export function Equipment() {
|
||||
onClick={() => {
|
||||
mutateDuel((draft) => {
|
||||
if (equipmentMatrix[rowIndex][columnIndex] === 1) {
|
||||
draft.protagonist!.equipment[rowIndex][columnIndex] = 0;
|
||||
draft.protagonist!.equipmentMatrix[rowIndex][
|
||||
columnIndex
|
||||
] = 0;
|
||||
} else {
|
||||
draft.protagonist!.equipment[rowIndex][columnIndex] = 1;
|
||||
draft.protagonist!.equipmentMatrix[rowIndex][
|
||||
columnIndex
|
||||
] = 1;
|
||||
}
|
||||
});
|
||||
}}
|
||||
|
||||
@@ -17,6 +17,7 @@ import { isExplosive } from '../../../../../../core/blitz/isExplosive';
|
||||
import { coefficient } from '../../../../../../core/blitzkrieg/coefficient';
|
||||
import { modelDefinitions } from '../../../../../../core/blitzkrieg/modelDefinitions';
|
||||
import { provisionDefinitions } from '../../../../../../core/blitzkrieg/provisionDefinitions';
|
||||
import { tankCharacteristics } from '../../../../../../core/blitzkrieg/tankCharacteristics';
|
||||
import {
|
||||
CREW_MEMBER_NAMES,
|
||||
GUN_TYPE_NAMES,
|
||||
@@ -24,7 +25,6 @@ import {
|
||||
} from '../../../../../../core/blitzkrieg/tankDefinitions/constants';
|
||||
import { useEquipment } from '../../../../../../hooks/useEquipment';
|
||||
import { useFullScreen } from '../../../../../../hooks/useFullScreen';
|
||||
import { useTankCharacteristics } from '../../../../../../hooks/useTankCharacteristics';
|
||||
import { mutateDuel, useDuel } from '../../../../../../stores/duel';
|
||||
import { useTankopediaTemporary } from '../../../../../../stores/tankopedia';
|
||||
import { Info } from './components/Info';
|
||||
@@ -53,7 +53,9 @@ export function Characteristics() {
|
||||
const crewMemberMastery = commanderMastery * 1.1;
|
||||
const consumables = useDuel((state) => state.protagonist!.consumables);
|
||||
const camouflage = useDuel((state) => state.protagonist!.camouflage);
|
||||
const equipmentMatrix = useDuel((state) => state.protagonist!.equipment);
|
||||
const equipmentMatrix = useDuel(
|
||||
(state) => state.protagonist!.equipmentMatrix,
|
||||
);
|
||||
const { tank, turret, gun, engine, track, shell } = useDuel(
|
||||
(state) => state.protagonist!,
|
||||
);
|
||||
@@ -64,24 +66,26 @@ export function Characteristics() {
|
||||
const tankModelDefinition = awaitedModelDefinitions[tank.id];
|
||||
const turretModelDefinition = tankModelDefinition.turrets[turret.id];
|
||||
const gunModelDefinition = turretModelDefinition.guns[gun.id];
|
||||
const stats = useTankCharacteristics({
|
||||
tank,
|
||||
camouflage,
|
||||
consumables,
|
||||
crewMastery,
|
||||
crewSkills,
|
||||
engine,
|
||||
equipmentMatrix,
|
||||
gun,
|
||||
provisions,
|
||||
shell,
|
||||
turret,
|
||||
track,
|
||||
stockEngine,
|
||||
stockGun,
|
||||
stockTrack,
|
||||
stockTurret,
|
||||
});
|
||||
const stats = use(
|
||||
tankCharacteristics({
|
||||
tank,
|
||||
camouflage,
|
||||
consumables,
|
||||
crewMastery,
|
||||
crewSkills,
|
||||
engine,
|
||||
equipmentMatrix,
|
||||
gun,
|
||||
provisions,
|
||||
shell,
|
||||
turret,
|
||||
track,
|
||||
stockEngine,
|
||||
stockGun,
|
||||
stockTrack,
|
||||
stockTurret,
|
||||
}),
|
||||
);
|
||||
|
||||
const hasSupercharger = useEquipment(107);
|
||||
const hasCalibratedShells = useEquipment(103);
|
||||
|
||||
@@ -73,7 +73,7 @@ export function Controls() {
|
||||
const hasImprovedVerticalStabilizer = await hasEquipment(
|
||||
122,
|
||||
duel.protagonist!.tank.equipment,
|
||||
duel.protagonist!.equipment,
|
||||
duel.protagonist!.equipmentMatrix,
|
||||
);
|
||||
|
||||
switch (event) {
|
||||
|
||||
@@ -166,7 +166,7 @@ export const TankModel = memo(() => {
|
||||
const hasImprovedVerticalStabilizer = await hasEquipment(
|
||||
122,
|
||||
duel.protagonist!.tank.equipment,
|
||||
duel.protagonist!.equipment,
|
||||
duel.protagonist!.equipmentMatrix,
|
||||
);
|
||||
[pitch, yaw] = applyPitchYawLimits(
|
||||
pitch,
|
||||
@@ -232,7 +232,7 @@ export const TankModel = memo(() => {
|
||||
const hasImprovedVerticalStabilizer = await hasEquipment(
|
||||
122,
|
||||
duel.protagonist!.tank.equipment,
|
||||
duel.protagonist!.equipment,
|
||||
duel.protagonist!.equipmentMatrix,
|
||||
);
|
||||
[pitch, yaw] = applyPitchYawLimits(
|
||||
pitch - event.movementY * (Math.PI / canvas.height),
|
||||
|
||||
@@ -159,7 +159,9 @@ export function RotationInputs({ isFullScreen }: RotationInputsProps) {
|
||||
active={hasCalibratedShells}
|
||||
onClick={() => {
|
||||
mutateDuel((draft) => {
|
||||
draft.antagonist!.equipment[0][0] = hasCalibratedShells ? 0 : 1;
|
||||
draft.antagonist!.equipmentMatrix[0][0] = hasCalibratedShells
|
||||
? 0
|
||||
: 1;
|
||||
});
|
||||
}}
|
||||
/>
|
||||
@@ -168,7 +170,9 @@ export function RotationInputs({ isFullScreen }: RotationInputsProps) {
|
||||
active={hasEnhancedArmor}
|
||||
onClick={() => {
|
||||
mutateDuel((draft) => {
|
||||
draft.protagonist!.equipment[1][1] = hasEnhancedArmor ? 0 : -1;
|
||||
draft.protagonist!.equipmentMatrix[1][1] = hasEnhancedArmor
|
||||
? 0
|
||||
: -1;
|
||||
});
|
||||
}}
|
||||
/>
|
||||
|
||||
Reference in new issue
Block a user