mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-25 03:29:51 +01:00
feat: shell swapping
This commit is contained in:
1 parent
32ee10445d
commit
371dcad568
4 files changed
+107
-73
No files matched your search
@@ -5,6 +5,7 @@ import { GLTFLoader } from 'three-stdlib';
|
|||||||
import { ArmorMesh } from '../../../../../../../components/ArmorMesh';
|
import { ArmorMesh } from '../../../../../../../components/ArmorMesh';
|
||||||
import { HeadsUpDisplay } from '../../../../../../../components/HeadsUpDisplay';
|
import { HeadsUpDisplay } from '../../../../../../../components/HeadsUpDisplay';
|
||||||
import { X_AXIS } from '../../../../../../../constants/axis';
|
import { X_AXIS } from '../../../../../../../constants/axis';
|
||||||
|
import { numericPenetration } from '../../../../../../../core/blitz/numericPenetration';
|
||||||
import { asset } from '../../../../../../../core/blitzkrieg/asset';
|
import { asset } from '../../../../../../../core/blitzkrieg/asset';
|
||||||
import {
|
import {
|
||||||
ModelDefinitions,
|
ModelDefinitions,
|
||||||
@@ -97,7 +98,7 @@ export function TankArmor(props: TankArmorProps) {
|
|||||||
key={node.uuid}
|
key={node.uuid}
|
||||||
geometry={(node as Mesh).geometry}
|
geometry={(node as Mesh).geometry}
|
||||||
thickness={thickness}
|
thickness={thickness}
|
||||||
penetration={252}
|
penetration={numericPenetration(antagonist.shell.penetration)}
|
||||||
ricochet={antagonist.shell.ricochet}
|
ricochet={antagonist.shell.ricochet}
|
||||||
caliber={antagonist.shell.caliber}
|
caliber={antagonist.shell.caliber}
|
||||||
normalization={antagonist.shell.normalization}
|
normalization={antagonist.shell.normalization}
|
||||||
@@ -123,7 +124,7 @@ export function TankArmor(props: TankArmorProps) {
|
|||||||
position={turretOrigin}
|
position={turretOrigin}
|
||||||
geometry={(node as Mesh).geometry}
|
geometry={(node as Mesh).geometry}
|
||||||
thickness={thickness}
|
thickness={thickness}
|
||||||
penetration={252}
|
penetration={numericPenetration(antagonist.shell.penetration)}
|
||||||
ricochet={antagonist.shell.ricochet}
|
ricochet={antagonist.shell.ricochet}
|
||||||
caliber={antagonist.shell.caliber}
|
caliber={antagonist.shell.caliber}
|
||||||
normalization={antagonist.shell.normalization}
|
normalization={antagonist.shell.normalization}
|
||||||
@@ -155,7 +156,7 @@ export function TankArmor(props: TankArmorProps) {
|
|||||||
position={turretOrigin.clone().add(gunOrigin)}
|
position={turretOrigin.clone().add(gunOrigin)}
|
||||||
geometry={(node as Mesh).geometry}
|
geometry={(node as Mesh).geometry}
|
||||||
thickness={thickness}
|
thickness={thickness}
|
||||||
penetration={252}
|
penetration={numericPenetration(antagonist.shell.penetration)}
|
||||||
ricochet={antagonist.shell.ricochet}
|
ricochet={antagonist.shell.ricochet}
|
||||||
caliber={antagonist.shell.caliber}
|
caliber={antagonist.shell.caliber}
|
||||||
normalization={antagonist.shell.normalization}
|
normalization={antagonist.shell.normalization}
|
||||||
|
|||||||
@@ -18,8 +18,7 @@ import {
|
|||||||
import { go } from 'fuzzysort';
|
import { go } from 'fuzzysort';
|
||||||
import { debounce } from 'lodash';
|
import { debounce } from 'lodash';
|
||||||
import { use, useRef, useState } from 'react';
|
import { use, useRef, useState } from 'react';
|
||||||
import { ModuleButtons } from '../../../../../components/ModuleButton';
|
import { ModuleButton } from '../../../../../components/ModuleButton';
|
||||||
import { asset } from '../../../../../core/blitzkrieg/asset';
|
|
||||||
import {
|
import {
|
||||||
SHELL_NAMES,
|
SHELL_NAMES,
|
||||||
tankDefinitions,
|
tankDefinitions,
|
||||||
@@ -169,7 +168,12 @@ export function VersusBar() {
|
|||||||
<Flex>
|
<Flex>
|
||||||
{antagonist.tank.turrets.map((turret, index) => (
|
{antagonist.tank.turrets.map((turret, index) => (
|
||||||
<Tooltip content={turret.name} key={turret.id}>
|
<Tooltip content={turret.name} key={turret.id}>
|
||||||
<ModuleButtons
|
<ModuleButton
|
||||||
|
rowChild
|
||||||
|
first={index === 0}
|
||||||
|
last={
|
||||||
|
index === antagonist.tank.turrets.length - 1
|
||||||
|
}
|
||||||
key={turret.id}
|
key={turret.id}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
mutateTankopedia((draft) => {
|
mutateTankopedia((draft) => {
|
||||||
@@ -184,24 +188,8 @@ export function VersusBar() {
|
|||||||
}}
|
}}
|
||||||
selected={antagonist.turret.id === turret.id}
|
selected={antagonist.turret.id === turret.id}
|
||||||
tier={turret.tier}
|
tier={turret.tier}
|
||||||
type="turret"
|
type="module"
|
||||||
style={{
|
module="turret"
|
||||||
margin: -0.5,
|
|
||||||
borderTopLeftRadius:
|
|
||||||
index === 0 ? undefined : 0,
|
|
||||||
borderBottomLeftRadius:
|
|
||||||
index === 0 ? undefined : 0,
|
|
||||||
borderTopRightRadius:
|
|
||||||
index ===
|
|
||||||
antagonist.tank.turrets.length - 1
|
|
||||||
? undefined
|
|
||||||
: 0,
|
|
||||||
borderBottomRightRadius:
|
|
||||||
index ===
|
|
||||||
antagonist.tank.turrets.length - 1
|
|
||||||
? undefined
|
|
||||||
: 0,
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
))}
|
))}
|
||||||
@@ -209,7 +197,12 @@ export function VersusBar() {
|
|||||||
<Flex>
|
<Flex>
|
||||||
{antagonist.turret.guns.map((gun, index) => (
|
{antagonist.turret.guns.map((gun, index) => (
|
||||||
<Tooltip content={gun.name} key={gun.id}>
|
<Tooltip content={gun.name} key={gun.id}>
|
||||||
<ModuleButtons
|
<ModuleButton
|
||||||
|
rowChild
|
||||||
|
first={index === 0}
|
||||||
|
last={
|
||||||
|
index === antagonist.turret.guns.length - 1
|
||||||
|
}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
mutateTankopedia((draft) => {
|
mutateTankopedia((draft) => {
|
||||||
if (!draft.areTanksAssigned) return;
|
if (!draft.areTanksAssigned) return;
|
||||||
@@ -219,24 +212,8 @@ export function VersusBar() {
|
|||||||
}}
|
}}
|
||||||
selected={antagonist.gun.id === gun.id}
|
selected={antagonist.gun.id === gun.id}
|
||||||
tier={gun.tier}
|
tier={gun.tier}
|
||||||
type="gun"
|
type="module"
|
||||||
style={{
|
module="gun"
|
||||||
margin: -0.5,
|
|
||||||
borderTopLeftRadius:
|
|
||||||
index === 0 ? undefined : 0,
|
|
||||||
borderBottomLeftRadius:
|
|
||||||
index === 0 ? undefined : 0,
|
|
||||||
borderTopRightRadius:
|
|
||||||
index ===
|
|
||||||
antagonist.turret.guns.length - 1
|
|
||||||
? undefined
|
|
||||||
: 0,
|
|
||||||
borderBottomRightRadius:
|
|
||||||
index ===
|
|
||||||
antagonist.turret.guns.length - 1
|
|
||||||
? undefined
|
|
||||||
: 0,
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
))}
|
))}
|
||||||
@@ -278,8 +255,27 @@ export function VersusBar() {
|
|||||||
<Text>Calibrated</Text>
|
<Text>Calibrated</Text>
|
||||||
</Flex>
|
</Flex>
|
||||||
|
|
||||||
<Flex gap="1">
|
<Flex>
|
||||||
<Button variant="solid" radius="small">
|
{antagonist.gun.shells.map((shell, index) => {
|
||||||
|
return (
|
||||||
|
<ModuleButton
|
||||||
|
selected={antagonist.shell.id === shell.id}
|
||||||
|
type="shell"
|
||||||
|
shell={shell.type}
|
||||||
|
rowChild
|
||||||
|
first={index === 0}
|
||||||
|
key={shell.id}
|
||||||
|
last={index === antagonist.gun.shells.length - 1}
|
||||||
|
onClick={() => {
|
||||||
|
mutateTankopedia((draft) => {
|
||||||
|
if (!draft.areTanksAssigned) return;
|
||||||
|
draft.antagonist.shell = shell;
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
{/* <Button variant="solid" radius="small">
|
||||||
<img src={asset('icons/shells/ap.webp')} width={24} height={24} />
|
<img src={asset('icons/shells/ap.webp')} width={24} height={24} />
|
||||||
</Button>
|
</Button>
|
||||||
<Button variant="soft" radius="small" color="gray">
|
<Button variant="soft" radius="small" color="gray">
|
||||||
@@ -291,7 +287,7 @@ export function VersusBar() {
|
|||||||
</Button>
|
</Button>
|
||||||
<Button variant="soft" radius="small" color="gray">
|
<Button variant="soft" radius="small" color="gray">
|
||||||
<img src={asset('icons/shells/he.webp')} width={24} height={24} />
|
<img src={asset('icons/shells/he.webp')} width={24} height={24} />
|
||||||
</Button>
|
</Button> */}
|
||||||
</Flex>
|
</Flex>
|
||||||
</Flex>
|
</Flex>
|
||||||
</Card>
|
</Card>
|
||||||
|
|||||||
@@ -1,20 +1,35 @@
|
|||||||
import { Button, Text } from '@radix-ui/themes';
|
import { Button, Text } from '@radix-ui/themes';
|
||||||
import { ComponentProps } from 'react';
|
import { ComponentProps } from 'react';
|
||||||
import { asset } from '../core/blitzkrieg/asset';
|
import { asset } from '../core/blitzkrieg/asset';
|
||||||
import { TIER_ROMAN_NUMERALS, Tier } from '../core/blitzkrieg/tankDefinitions';
|
import {
|
||||||
|
ShellType,
|
||||||
|
TIER_ROMAN_NUMERALS,
|
||||||
|
Tier,
|
||||||
|
} from '../core/blitzkrieg/tankDefinitions';
|
||||||
|
|
||||||
interface ModuleButtonProps
|
type ModuleButtonProps = Omit<ComponentProps<typeof Button>, 'type'> & {
|
||||||
extends Omit<ComponentProps<typeof Button>, 'type'> {
|
|
||||||
type: string;
|
|
||||||
tier: Tier;
|
|
||||||
selected?: boolean;
|
selected?: boolean;
|
||||||
}
|
first?: boolean;
|
||||||
|
last?: boolean;
|
||||||
|
rowChild?: boolean;
|
||||||
|
} & (
|
||||||
|
| {
|
||||||
|
type: 'module';
|
||||||
|
module: string;
|
||||||
|
tier: Tier;
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
type: 'shell';
|
||||||
|
shell: ShellType;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
export function ModuleButtons({
|
export function ModuleButton({
|
||||||
type,
|
|
||||||
tier,
|
|
||||||
selected,
|
selected,
|
||||||
style,
|
style,
|
||||||
|
first = true,
|
||||||
|
last = true,
|
||||||
|
rowChild,
|
||||||
...props
|
...props
|
||||||
}: ModuleButtonProps) {
|
}: ModuleButtonProps) {
|
||||||
return (
|
return (
|
||||||
@@ -27,34 +42,51 @@ export function ModuleButtons({
|
|||||||
width: 48,
|
width: 48,
|
||||||
height: 40,
|
height: 40,
|
||||||
position: 'relative',
|
position: 'relative',
|
||||||
|
borderTopLeftRadius: first ? undefined : 0,
|
||||||
|
borderTopRightRadius: last ? undefined : 0,
|
||||||
|
borderBottomLeftRadius: first ? undefined : 0,
|
||||||
|
borderBottomRightRadius: last ? undefined : 0,
|
||||||
|
margin: rowChild ? -0.5 : 'unset',
|
||||||
...style,
|
...style,
|
||||||
}}
|
}}
|
||||||
{...props}
|
{...(props as unknown as ComponentProps<typeof Button>)}
|
||||||
>
|
>
|
||||||
<img
|
<img
|
||||||
src={asset(`icons/modules/${type}.webp`)}
|
src={asset(
|
||||||
|
props.type === 'module'
|
||||||
|
? `icons/modules/${props.module}.webp`
|
||||||
|
: `icons/shells/${props.shell}.webp`,
|
||||||
|
)}
|
||||||
style={{
|
style={{
|
||||||
width: 32,
|
width: 32,
|
||||||
height: 32,
|
height: 32,
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
top: '50%',
|
...(props.type === 'module'
|
||||||
left: '50%',
|
? {
|
||||||
transform: 'translate(calc(-50% + 2px), calc(-50% + 2px))',
|
top: '50%',
|
||||||
|
left: '50%',
|
||||||
|
transform: 'translate(calc(-50% + 2px), calc(-50% + 2px))',
|
||||||
|
}
|
||||||
|
: {
|
||||||
|
transform: 'scale(0.75)',
|
||||||
|
}),
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<Text
|
{props.type === 'module' && (
|
||||||
size="1"
|
<Text
|
||||||
weight="bold"
|
size="1"
|
||||||
style={{
|
weight="bold"
|
||||||
zIndex: 1,
|
style={{
|
||||||
position: 'absolute',
|
zIndex: 1,
|
||||||
top: '50%',
|
position: 'absolute',
|
||||||
right: 8,
|
top: '50%',
|
||||||
textAlign: 'right',
|
right: 8,
|
||||||
}}
|
textAlign: 'right',
|
||||||
>
|
}}
|
||||||
{TIER_ROMAN_NUMERALS[tier]}
|
>
|
||||||
</Text>
|
{TIER_ROMAN_NUMERALS[props.tier]}
|
||||||
|
</Text>
|
||||||
|
)}
|
||||||
</Button>
|
</Button>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
import { Vector2Tuple } from 'three';
|
||||||
|
|
||||||
|
export function numericPenetration(penetration: number | Vector2Tuple) {
|
||||||
|
return typeof penetration === 'number' ? penetration : penetration[0];
|
||||||
|
}
|
||||||
Reference in new issue
Block a user