mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-24 20:19:49 +02:00
feat: module tree
This commit is contained in:
1 parent
89e97f484b
commit
7af5d5f465
4 files changed
+192
-32
No files matched your search
@@ -1,31 +1,84 @@
|
|||||||
import { Heading } from '@radix-ui/themes';
|
import { Flex, Heading } from '@radix-ui/themes';
|
||||||
import { use } from 'react';
|
import { use } from 'react';
|
||||||
|
import { ModuleButton } from '../../../../../../components/ModuleButtons/ModuleButton';
|
||||||
import PageWrapper from '../../../../../../components/PageWrapper';
|
import PageWrapper from '../../../../../../components/PageWrapper';
|
||||||
import {
|
import {
|
||||||
EngineDefinition,
|
ModuleDefinition,
|
||||||
GunDefinition,
|
|
||||||
ModuleType,
|
ModuleType,
|
||||||
|
TankDefinition,
|
||||||
tankDefinitions,
|
tankDefinitions,
|
||||||
TrackDefinition,
|
|
||||||
TurretDefinition,
|
|
||||||
Unlock,
|
Unlock,
|
||||||
} from '../../../../../../core/blitzkit/tankDefinitions';
|
} from '../../../../../../core/blitzkit/tankDefinitions';
|
||||||
import { useDuel } from '../../../../../../stores/duel';
|
import { TIER_ROMAN_NUMERALS } from '../../../../../../core/blitzkit/tankDefinitions/constants';
|
||||||
|
import { mutateDuel, useDuel } from '../../../../../../stores/duel';
|
||||||
|
import { TreeArrow } from './TechTreeSection';
|
||||||
|
|
||||||
export function ModulesSection() {
|
export function ModulesSection() {
|
||||||
const awaitedTankDefinitions = use(tankDefinitions);
|
const awaitedTankDefinitions = use(tankDefinitions);
|
||||||
const tank = useDuel((state) => state.protagonist!.tank);
|
const tank = useDuel((state) => state.protagonist!.tank);
|
||||||
|
const turret = useDuel((state) => state.protagonist!.turret);
|
||||||
|
const gun = useDuel((state) => state.protagonist!.gun);
|
||||||
|
const engine = useDuel((state) => state.protagonist!.engine);
|
||||||
|
const track = useDuel((state) => state.protagonist!.track);
|
||||||
|
const turret0 = tank.turrets[0];
|
||||||
|
const gun0 = turret0.guns[0];
|
||||||
|
const engine0 = tank.engines[0];
|
||||||
|
const track0 = tank.tracks[0];
|
||||||
|
|
||||||
|
function setByUnlock(unlock: Unlock) {
|
||||||
|
mutateDuel((draft) => {
|
||||||
|
if (unlock.type === 'turret') {
|
||||||
|
draft.protagonist!.turret = draft.protagonist!.tank.turrets.find(
|
||||||
|
(turret) => turret.id === unlock.id,
|
||||||
|
)!;
|
||||||
|
|
||||||
|
if (
|
||||||
|
!draft.protagonist!.turret.guns.some(
|
||||||
|
(gun) => gun.id === draft.protagonist!.gun.id,
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
draft.protagonist!.gun = draft.protagonist!.turret.guns.at(-1)!;
|
||||||
|
draft.protagonist!.shell = draft.protagonist!.gun.shells.at(-1)!;
|
||||||
|
}
|
||||||
|
} else if (unlock.type === 'gun') {
|
||||||
|
const gunInTurret = draft.protagonist!.turret.guns.find(
|
||||||
|
(gun) => gun.id === unlock.id,
|
||||||
|
);
|
||||||
|
if (gunInTurret) {
|
||||||
|
draft.protagonist!.gun = gunInTurret;
|
||||||
|
draft.protagonist!.shell = gunInTurret.shells.at(-1)!;
|
||||||
|
} else {
|
||||||
|
// TODO: warn somehow?
|
||||||
|
const suitableTurret = draft.protagonist!.tank.turrets.find(
|
||||||
|
(turret) => turret.guns.some((gun) => gun.id === unlock.id),
|
||||||
|
)!;
|
||||||
|
const gunInSuitableTurret = suitableTurret.guns.find(
|
||||||
|
(gun) => gun.id === unlock.id,
|
||||||
|
)!;
|
||||||
|
|
||||||
|
draft.protagonist!.turret = suitableTurret;
|
||||||
|
draft.protagonist!.gun = gunInSuitableTurret;
|
||||||
|
draft.protagonist!.shell = gunInSuitableTurret.shells.at(-1)!;
|
||||||
|
}
|
||||||
|
} else if (unlock.type === 'engine') {
|
||||||
|
draft.protagonist!.engine = draft.protagonist!.tank.engines.find(
|
||||||
|
(engine) => engine.id === unlock.id,
|
||||||
|
)!;
|
||||||
|
} else if (unlock.type === 'chassis') {
|
||||||
|
draft.protagonist!.track = draft.protagonist!.tank.tracks.find(
|
||||||
|
(track) => track.id === unlock.id,
|
||||||
|
)!;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function tree(type: ModuleType, unlocks: Unlock[]) {
|
function tree(type: ModuleType, unlocks: Unlock[]) {
|
||||||
return (
|
return (
|
||||||
<ul>
|
<Flex direction="column" gap="2">
|
||||||
{unlocks.map((unlock) => {
|
{unlocks.map((unlock) => {
|
||||||
let module:
|
let module: ModuleDefinition | TankDefinition | undefined = undefined;
|
||||||
| TrackDefinition
|
|
||||||
| EngineDefinition
|
console.log(unlock.type);
|
||||||
| TurretDefinition
|
|
||||||
| GunDefinition
|
|
||||||
| undefined = undefined;
|
|
||||||
|
|
||||||
if (unlock.type === 'chassis') {
|
if (unlock.type === 'chassis') {
|
||||||
module = tank.tracks.find((track) => track.id === unlock.id)!;
|
module = tank.tracks.find((track) => track.id === unlock.id)!;
|
||||||
@@ -43,31 +96,131 @@ export function ModulesSection() {
|
|||||||
|
|
||||||
if (module === undefined) return null;
|
if (module === undefined) return null;
|
||||||
|
|
||||||
|
const unlocksFiltered = (module as ModuleDefinition).unlocks?.filter(
|
||||||
|
({ type }) => type !== 'vehicle',
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<li>
|
<Flex align="center" gap="2">
|
||||||
{unlock.type} {module.name}
|
<ModuleButton
|
||||||
{module.unlocks && tree(type, module.unlocks)}
|
first
|
||||||
</li>
|
last
|
||||||
|
module={unlock.type}
|
||||||
|
discriminator={TIER_ROMAN_NUMERALS[module.tier]}
|
||||||
|
selected={
|
||||||
|
(unlock.type === 'turret'
|
||||||
|
? turret.id
|
||||||
|
: unlock.type === 'gun'
|
||||||
|
? gun.id
|
||||||
|
: unlock.type === 'engine'
|
||||||
|
? engine.id
|
||||||
|
: unlock.type === 'chassis'
|
||||||
|
? track.id
|
||||||
|
: -1) === unlock.id
|
||||||
|
}
|
||||||
|
onClick={() => setByUnlock(unlock)}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{unlocksFiltered && unlocksFiltered.length > 0 && (
|
||||||
|
<>
|
||||||
|
<TreeArrow style={{ width: 32 }} />
|
||||||
|
{tree(type, (module as ModuleDefinition).unlocks!)}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</Flex>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</ul>
|
</Flex>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PageWrapper>
|
<PageWrapper>
|
||||||
<Heading>turret0</Heading>
|
<Heading>Modules</Heading>
|
||||||
{tank.turrets[0].unlocks && tree('turret', tank.turrets[0].unlocks)}
|
|
||||||
|
|
||||||
<Heading>gun0</Heading>
|
<Flex direction="column" gap="2">
|
||||||
{tank.turrets[0].guns[0].unlocks &&
|
<Flex align="center" gap="2">
|
||||||
tree('gun', tank.turrets[0].guns[0].unlocks)}
|
<ModuleButton
|
||||||
|
module="turret"
|
||||||
|
first
|
||||||
|
last
|
||||||
|
discriminator={TIER_ROMAN_NUMERALS[turret0.tier]}
|
||||||
|
selected={turret0.id === turret.id}
|
||||||
|
onClick={() => setByUnlock({ id: turret0.id, type: 'turret' })}
|
||||||
|
/>
|
||||||
|
|
||||||
<Heading>engine0</Heading>
|
{turret0.unlocks && (
|
||||||
{tank.engines[0].unlocks && tree('engine', tank.engines[0].unlocks)}
|
<>
|
||||||
|
<TreeArrow style={{ width: 32, flex: undefined }} />
|
||||||
|
{tree('turret', turret0.unlocks)}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</Flex>
|
||||||
|
|
||||||
<Heading>track0</Heading>
|
<Flex align="center" gap="2">
|
||||||
{tank.tracks[0].unlocks && tree('chassis', tank.tracks[0].unlocks)}
|
<ModuleButton
|
||||||
|
module="gun"
|
||||||
|
first
|
||||||
|
last
|
||||||
|
discriminator={TIER_ROMAN_NUMERALS[gun0.tier]}
|
||||||
|
selected={gun0.id === gun.id}
|
||||||
|
onClick={() => setByUnlock({ id: gun0.id, type: 'gun' })}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{gun0.unlocks && (
|
||||||
|
<>
|
||||||
|
<TreeArrow style={{ width: 32, flex: undefined }} />
|
||||||
|
{tree('gun', gun0.unlocks)}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</Flex>
|
||||||
|
|
||||||
|
<Flex align="center" gap="2">
|
||||||
|
<ModuleButton
|
||||||
|
module="engine"
|
||||||
|
first
|
||||||
|
last
|
||||||
|
discriminator={TIER_ROMAN_NUMERALS[engine0.tier]}
|
||||||
|
selected={engine0.id === engine.id}
|
||||||
|
onClick={() => setByUnlock({ id: engine0.id, type: 'engine' })}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{engine0.unlocks && (
|
||||||
|
<>
|
||||||
|
<TreeArrow style={{ width: 32, flex: undefined }} />
|
||||||
|
{tree('engine', engine0.unlocks)}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</Flex>
|
||||||
|
|
||||||
|
<Flex align="center" gap="2">
|
||||||
|
<ModuleButton
|
||||||
|
module="chassis"
|
||||||
|
first
|
||||||
|
last
|
||||||
|
discriminator={TIER_ROMAN_NUMERALS[track0.tier]}
|
||||||
|
selected={track0.id === track.id}
|
||||||
|
onClick={() => setByUnlock({ id: track0.id, type: 'chassis' })}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{track0.unlocks && (
|
||||||
|
<>
|
||||||
|
<TreeArrow style={{ width: 32, flex: undefined }} />
|
||||||
|
{tree('chassis', track0.unlocks)}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</Flex>
|
||||||
|
|
||||||
|
{/* <Heading>gun0</Heading>
|
||||||
|
{tank.turrets[0].guns[0].unlocks &&
|
||||||
|
tree('gun', tank.turrets[0].guns[0].unlocks)}
|
||||||
|
|
||||||
|
<Heading>engine0</Heading>
|
||||||
|
{tank.engines[0].unlocks && tree('engine', tank.engines[0].unlocks)}
|
||||||
|
|
||||||
|
<Heading>track0</Heading>
|
||||||
|
{tank.tracks[0].unlocks && tree('chassis', tank.tracks[0].unlocks)} */}
|
||||||
|
</Flex>
|
||||||
</PageWrapper>
|
</PageWrapper>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -1,20 +1,22 @@
|
|||||||
import { ChevronRightIcon } from '@radix-ui/react-icons';
|
import { ChevronRightIcon } from '@radix-ui/react-icons';
|
||||||
import { Flex, Heading, Text } from '@radix-ui/themes';
|
import { Flex, Heading, Text } from '@radix-ui/themes';
|
||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
import { use } from 'react';
|
import { ComponentProps, use } from 'react';
|
||||||
import PageWrapper from '../../../../../../components/PageWrapper';
|
import PageWrapper from '../../../../../../components/PageWrapper';
|
||||||
import { asset } from '../../../../../../core/blitzkit/asset';
|
import { asset } from '../../../../../../core/blitzkit/asset';
|
||||||
import { tankDefinitions } from '../../../../../../core/blitzkit/tankDefinitions';
|
import { tankDefinitions } from '../../../../../../core/blitzkit/tankDefinitions';
|
||||||
import { TIER_ROMAN_NUMERALS } from '../../../../../../core/blitzkit/tankDefinitions/constants';
|
import { TIER_ROMAN_NUMERALS } from '../../../../../../core/blitzkit/tankDefinitions/constants';
|
||||||
import { useDuel } from '../../../../../../stores/duel';
|
import { useDuel } from '../../../../../../stores/duel';
|
||||||
|
|
||||||
function Arrow() {
|
export function TreeArrow({ style, ...props }: ComponentProps<typeof Text>) {
|
||||||
return (
|
return (
|
||||||
<Text
|
<Text
|
||||||
color="gray"
|
color="gray"
|
||||||
style={{
|
style={{
|
||||||
flex: 1,
|
flex: 1,
|
||||||
|
...style,
|
||||||
}}
|
}}
|
||||||
|
{...props}
|
||||||
>
|
>
|
||||||
<Flex
|
<Flex
|
||||||
style={{
|
style={{
|
||||||
@@ -130,7 +132,7 @@ export function TechTreeSection() {
|
|||||||
))}
|
))}
|
||||||
</Flex>
|
</Flex>
|
||||||
|
|
||||||
<Arrow />
|
<TreeArrow />
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
@@ -160,7 +162,7 @@ export function TechTreeSection() {
|
|||||||
|
|
||||||
{tank.successors && (
|
{tank.successors && (
|
||||||
<>
|
<>
|
||||||
<Arrow />
|
<TreeArrow />
|
||||||
|
|
||||||
<Flex
|
<Flex
|
||||||
wrap="wrap"
|
wrap="wrap"
|
||||||
|
|||||||
@@ -62,8 +62,8 @@ export default function Page({ params }: { params: { id: string } }) {
|
|||||||
<>
|
<>
|
||||||
<HeroSection />
|
<HeroSection />
|
||||||
{/* <TankopediaPlug /> */}
|
{/* <TankopediaPlug /> */}
|
||||||
<TechTreeSection />
|
|
||||||
<ModulesSection />
|
<ModulesSection />
|
||||||
|
<TechTreeSection />
|
||||||
{/* <CharacteristicsSection />
|
{/* <CharacteristicsSection />
|
||||||
<TankopediaSeparator /> */}
|
<TankopediaSeparator /> */}
|
||||||
<Videos />
|
<Videos />
|
||||||
|
|||||||
@@ -24,6 +24,11 @@ export interface Crew {
|
|||||||
count?: number;
|
count?: number;
|
||||||
substitute?: CrewMember[];
|
substitute?: CrewMember[];
|
||||||
}
|
}
|
||||||
|
export type ModuleDefinition =
|
||||||
|
| TrackDefinition
|
||||||
|
| EngineDefinition
|
||||||
|
| TurretDefinition
|
||||||
|
| GunDefinition;
|
||||||
export interface TankDefinition {
|
export interface TankDefinition {
|
||||||
id: number;
|
id: number;
|
||||||
description?: string;
|
description?: string;
|
||||||
|
|||||||
Reference in new issue
Block a user