feat: better modules

This commit is contained in:
TrèsAbhi committed 2024-05-04 12:05:37 -05:00
1 parent 7af5d5f465
commit d0743b54e0
3 files changed
+170 -48

No files matched your search

+18 -7
View File
@@ -35,6 +35,7 @@ import {
TankDefinitionPrice, TankDefinitionPrice,
TankDefinitions, TankDefinitions,
Tier, Tier,
Unlock,
} from '../../src/core/blitzkit/tankDefinitions'; } from '../../src/core/blitzkit/tankDefinitions';
import { DATA, POI } from './constants'; import { DATA, POI } from './constants';
import { Avatar } from './skillIcons'; import { Avatar } from './skillIcons';
@@ -86,7 +87,7 @@ type VehicleDefinitionArmor = Record<
number | { vehicleDamageFactor: 0; '#text': number } number | { vehicleDamageFactor: 0; '#text': number }
>; >;
interface UnlocksInner { interface UnlocksInner {
cost: number; cost: number | string;
'#text': number; '#text': number;
} }
type Unlocks = { type Unlocks = {
@@ -477,7 +478,17 @@ export async function definitions(production: boolean) {
return { return {
type: typeTyped, type: typeTyped,
id: toUniqueId(nation, rawId!), id: toUniqueId(nation, rawId!),
}; cost: {
type:
typeof item.cost === 'number'
? 'xp'
: item.cost.split(':')[0],
value:
typeof item.cost === 'number'
? item.cost
: Number(item.cost.split(':')[1]),
},
} satisfies Unlock;
}), }),
) )
.flat(); .flat();
@@ -948,7 +959,7 @@ export async function definitions(production: boolean) {
const currentTank = tankDefinitions[tankId]; const currentTank = tankDefinitions[tankId];
const successorId = toUniqueId(nation, tankListEntry.id); const successorId = toUniqueId(nation, tankListEntry.id);
tankXps.set(successorId, vehicle.cost); tankXps.set(successorId, vehicle.cost as number);
if (currentTank.successors === undefined) { if (currentTank.successors === undefined) {
currentTank.successors = []; currentTank.successors = [];
@@ -962,7 +973,7 @@ export async function definitions(production: boolean) {
case 'gun': { case 'gun': {
gunXps.set( gunXps.set(
toUniqueId(nation, gunList.root.ids[vehicle['#text']]), toUniqueId(nation, gunList.root.ids[vehicle['#text']]),
vehicle.cost, vehicle.cost as number,
); );
break; break;
} }
@@ -970,7 +981,7 @@ export async function definitions(production: boolean) {
case 'turret': { case 'turret': {
turretXps.set( turretXps.set(
toUniqueId(nation, turretList.root.ids[vehicle['#text']]), toUniqueId(nation, turretList.root.ids[vehicle['#text']]),
vehicle.cost, vehicle.cost as number,
); );
break; break;
} }
@@ -978,7 +989,7 @@ export async function definitions(production: boolean) {
case 'engine': { case 'engine': {
engineXps.set( engineXps.set(
toUniqueId(nation, enginesList.root.ids[vehicle['#text']]), toUniqueId(nation, enginesList.root.ids[vehicle['#text']]),
vehicle.cost, vehicle.cost as number,
); );
break; break;
} }
@@ -986,7 +997,7 @@ export async function definitions(production: boolean) {
case 'chassis': { case 'chassis': {
trackXps.set( trackXps.set(
toUniqueId(nation, chassisList.root.ids[vehicle['#text']]), toUniqueId(nation, chassisList.root.ids[vehicle['#text']]),
vehicle.cost, vehicle.cost as number,
); );
break; break;
} }
@@ -1,18 +1,106 @@
import { Flex, Heading } from '@radix-ui/themes'; import { Flex, Heading, IconButton, Text } from '@radix-ui/themes';
import Link from 'next/link';
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 { asset } from '../../../../../../core/blitzkit/asset';
import { import {
ModuleDefinition, ModuleDefinition,
ModuleType, ModuleType,
TankDefinition, TankDefinition,
tankDefinitions, tankDefinitions,
Tier,
Unlock, Unlock,
} from '../../../../../../core/blitzkit/tankDefinitions'; } from '../../../../../../core/blitzkit/tankDefinitions';
import { TIER_ROMAN_NUMERALS } from '../../../../../../core/blitzkit/tankDefinitions/constants'; import { TIER_ROMAN_NUMERALS } from '../../../../../../core/blitzkit/tankDefinitions/constants';
import { tankIcon } from '../../../../../../core/blitzkit/tankIcon';
import { mutateDuel, useDuel } from '../../../../../../stores/duel'; import { mutateDuel, useDuel } from '../../../../../../stores/duel';
import { TreeArrow } from './TechTreeSection'; import { TreeArrow } from './TechTreeSection';
function ModuleButton({
tier,
selected,
unlock,
onClick,
}: {
unlock: Unlock;
tier: Tier;
selected: boolean;
onClick: () => void;
}) {
const numberFormat = Intl.NumberFormat(undefined, {
notation: 'compact',
maximumFractionDigits: 0,
});
const button = (
<IconButton
size="4"
radius="small"
variant={selected ? 'surface' : 'soft'}
color={selected ? undefined : 'gray'}
onClick={onClick}
style={{
position: 'relative',
}}
>
<Text
size="1"
color="gray"
style={{
position: 'absolute',
left: 4,
top: 4,
}}
>
{TIER_ROMAN_NUMERALS[tier]}
</Text>
{unlock.cost.value > 0 && (
<Flex
style={{
position: 'absolute',
left: '50%',
bottom: 4,
transform: 'translateX(-50%)',
}}
align="center"
>
<Text size="1" color="gray">
{numberFormat.format(unlock.cost.value)}
</Text>
<img
src={asset(`icons/currencies/${unlock.cost.type}.webp`)}
style={{
width: 12,
height: 12,
objectFit: 'contain',
}}
/>
</Flex>
)}
<img
src={
unlock.type === 'vehicle'
? tankIcon(unlock.id)
: asset(`icons/modules/${unlock.type}.webp`)
}
style={{
width: 32,
height: 32,
objectFit: 'contain',
}}
/>
</IconButton>
);
return unlock.type === 'vehicle' ? (
<Link href={`/tools/tankopedia/${unlock.id}`}>{button}</Link>
) : (
button
);
}
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);
@@ -92,21 +180,17 @@ export function ModulesSection() {
turret.guns.some((gun) => gun.id === unlock.id), turret.guns.some((gun) => gun.id === unlock.id),
)! )!
.guns.find((gun) => gun.id === unlock.id)!; .guns.find((gun) => gun.id === unlock.id)!;
} else if (unlock.type === 'vehicle') {
module = awaitedTankDefinitions[unlock.id];
} }
if (module === undefined) return null; if (module === undefined) return null;
const unlocksFiltered = (module as ModuleDefinition).unlocks?.filter(
({ type }) => type !== 'vehicle',
);
return ( return (
<Flex align="center" gap="2"> <Flex align="center" gap="2">
<ModuleButton <ModuleButton
first unlock={unlock}
last tier={module.tier}
module={unlock.type}
discriminator={TIER_ROMAN_NUMERALS[module.tier]}
selected={ selected={
(unlock.type === 'turret' (unlock.type === 'turret'
? turret.id ? turret.id
@@ -121,7 +205,7 @@ export function ModulesSection() {
onClick={() => setByUnlock(unlock)} onClick={() => setByUnlock(unlock)}
/> />
{unlocksFiltered && unlocksFiltered.length > 0 && ( {(module as ModuleDefinition).unlocks && (
<> <>
<TreeArrow style={{ width: 32 }} /> <TreeArrow style={{ width: 32 }} />
{tree(type, (module as ModuleDefinition).unlocks!)} {tree(type, (module as ModuleDefinition).unlocks!)}
@@ -141,12 +225,20 @@ export function ModulesSection() {
<Flex direction="column" gap="2"> <Flex direction="column" gap="2">
<Flex align="center" gap="2"> <Flex align="center" gap="2">
<ModuleButton <ModuleButton
module="turret" unlock={{
first type: 'turret',
last id: turret0.id,
discriminator={TIER_ROMAN_NUMERALS[turret0.tier]} cost: { type: 'xp', value: 0 },
}}
tier={turret0.tier}
selected={turret0.id === turret.id} selected={turret0.id === turret.id}
onClick={() => setByUnlock({ id: turret0.id, type: 'turret' })} onClick={() =>
setByUnlock({
id: turret0.id,
type: 'turret',
cost: { type: 'xp', value: 0 },
})
}
/> />
{turret0.unlocks && ( {turret0.unlocks && (
@@ -159,12 +251,20 @@ export function ModulesSection() {
<Flex align="center" gap="2"> <Flex align="center" gap="2">
<ModuleButton <ModuleButton
module="gun" unlock={{
first type: 'gun',
last id: gun0.id,
discriminator={TIER_ROMAN_NUMERALS[gun0.tier]} cost: { type: 'xp', value: 0 },
}}
tier={gun0.tier}
selected={gun0.id === gun.id} selected={gun0.id === gun.id}
onClick={() => setByUnlock({ id: gun0.id, type: 'gun' })} onClick={() =>
setByUnlock({
id: gun0.id,
type: 'gun',
cost: { type: 'xp', value: 0 },
})
}
/> />
{gun0.unlocks && ( {gun0.unlocks && (
@@ -177,12 +277,20 @@ export function ModulesSection() {
<Flex align="center" gap="2"> <Flex align="center" gap="2">
<ModuleButton <ModuleButton
module="engine" unlock={{
first type: 'engine',
last id: engine0.id,
discriminator={TIER_ROMAN_NUMERALS[engine0.tier]} cost: { type: 'xp', value: 0 },
}}
tier={engine0.tier}
selected={engine0.id === engine.id} selected={engine0.id === engine.id}
onClick={() => setByUnlock({ id: engine0.id, type: 'engine' })} onClick={() =>
setByUnlock({
id: engine0.id,
type: 'engine',
cost: { type: 'xp', value: 0 },
})
}
/> />
{engine0.unlocks && ( {engine0.unlocks && (
@@ -195,12 +303,20 @@ export function ModulesSection() {
<Flex align="center" gap="2"> <Flex align="center" gap="2">
<ModuleButton <ModuleButton
module="chassis" unlock={{
first type: 'chassis',
last id: track0.id,
discriminator={TIER_ROMAN_NUMERALS[track0.tier]} cost: { type: 'xp', value: 0 },
}}
tier={track0.tier}
selected={track0.id === track.id} selected={track0.id === track.id}
onClick={() => setByUnlock({ id: track0.id, type: 'chassis' })} onClick={() =>
setByUnlock({
id: track0.id,
type: 'chassis',
cost: { type: 'xp', value: 0 },
})
}
/> />
{track0.unlocks && ( {track0.unlocks && (
@@ -210,16 +326,6 @@ export function ModulesSection() {
</> </>
)} )}
</Flex> </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> </Flex>
</PageWrapper> </PageWrapper>
); );
@@ -18,6 +18,11 @@ export type ModuleType = 'vehicle' | 'engine' | 'chassis' | 'turret' | 'gun';
export interface Unlock { export interface Unlock {
type: ModuleType; type: ModuleType;
id: number; id: number;
cost: {
// string being the season coins
type: 'xp' | string;
value: number;
};
} }
export interface Crew { export interface Crew {
type: CrewMember; type: CrewMember;