mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-21 10:47:04 +02:00
feat: united duel data
This commit is contained in:
1 parent
da767213cb
commit
7e92f8ac50
23 files changed
+249
-249
No files matched your search
@@ -21,13 +21,13 @@ import {
|
||||
import { mutateDuel, useDuel } from '../../../../../../stores/duel';
|
||||
import {
|
||||
mutateTankopediaTemporary,
|
||||
useTankopediaTemporary,
|
||||
useTankopediaPersistent,
|
||||
} from '../../../../../../stores/tankopedia';
|
||||
import { TankSearch } from '../../../components/TankSearch';
|
||||
|
||||
export function AntagonistBar() {
|
||||
const antagonist = useDuel((state) => state.antagonist!);
|
||||
const mode = useTankopediaTemporary((state) => state.mode);
|
||||
const mode = useTankopediaPersistent((state) => state.mode);
|
||||
const [tab, setTab] = useState('search');
|
||||
const [antagonistSelectorOpen, setAntagonistSelectorVisible] =
|
||||
useState(false);
|
||||
|
||||
+10
-13
@@ -4,17 +4,13 @@ import { ConsumableButton } from '../../../../../../../components/ModuleButtons/
|
||||
import { checkConsumableProvisionInclusivity } from '../../../../../../../core/blitzkrieg/checkConsumableProvisionInclusivity';
|
||||
import { consumableDefinitions } from '../../../../../../../core/blitzkrieg/consumableDefinitions';
|
||||
import { useEquipment } from '../../../../../../../hooks/useEquipment';
|
||||
import { useDuel } from '../../../../../../../stores/duel';
|
||||
import {
|
||||
mutateTankopediaTemporary,
|
||||
useTankopediaTemporary,
|
||||
} from '../../../../../../../stores/tankopedia';
|
||||
import { mutateDuel, useDuel } from '../../../../../../../stores/duel';
|
||||
import { ConfigurationChildWrapper } from './ConfigurationChildWrapper';
|
||||
|
||||
export function Consumables() {
|
||||
const protagonist = useDuel((state) => state.protagonist!);
|
||||
const awaitedConsumableDefinitions = use(consumableDefinitions);
|
||||
const consumables = useTankopediaTemporary((state) => state.consumables);
|
||||
const consumables = useDuel((state) => state.protagonist!.consumables);
|
||||
const consumablesList = Object.values(awaitedConsumableDefinitions).filter(
|
||||
(consumable) =>
|
||||
checkConsumableProvisionInclusivity(
|
||||
@@ -23,8 +19,8 @@ export function Consumables() {
|
||||
protagonist.gun,
|
||||
),
|
||||
);
|
||||
const cooldownBooster = useTankopediaTemporary(
|
||||
(state) => state.cooldownBooster,
|
||||
const cooldownBooster = useDuel(
|
||||
(state) => state.protagonist!.cooldownBooster,
|
||||
);
|
||||
const hasConsumableDeliverySystem = useEquipment(118);
|
||||
const hasHighEndConsumables = useEquipment(101);
|
||||
@@ -59,13 +55,14 @@ export function Consumables() {
|
||||
consumable={consumable.id}
|
||||
selected={selected}
|
||||
onClick={() => {
|
||||
mutateTankopediaTemporary((draft) => {
|
||||
mutateDuel((draft) => {
|
||||
if (selected) {
|
||||
draft.consumables = draft.consumables.filter(
|
||||
(id) => id !== consumable.id,
|
||||
);
|
||||
draft.protagonist!.consumables =
|
||||
draft.protagonist!.consumables.filter(
|
||||
(id) => id !== consumable.id,
|
||||
);
|
||||
} else {
|
||||
draft.consumables.push(consumable.id);
|
||||
draft.protagonist!.consumables.push(consumable.id);
|
||||
}
|
||||
});
|
||||
}}
|
||||
|
||||
@@ -2,11 +2,7 @@ import { Flex, Heading } from '@radix-ui/themes';
|
||||
import { use } from 'react';
|
||||
import { EquipmentButton } from '../../../../../../../components/ModuleButtons/EquipmentButton';
|
||||
import { equipmentDefinitions } from '../../../../../../../core/blitzkrieg/equipmentDefinitions';
|
||||
import { useDuel } from '../../../../../../../stores/duel';
|
||||
import {
|
||||
mutateTankopediaTemporary,
|
||||
useTankopediaTemporary,
|
||||
} from '../../../../../../../stores/tankopedia';
|
||||
import { mutateDuel, useDuel } from '../../../../../../../stores/duel';
|
||||
import { ConfigurationChildWrapper } from './ConfigurationChildWrapper';
|
||||
|
||||
export function Equipments() {
|
||||
@@ -14,9 +10,7 @@ export function Equipments() {
|
||||
const awaitedEquipmentDefinitions = use(equipmentDefinitions);
|
||||
const equipmentRows =
|
||||
awaitedEquipmentDefinitions.presets[protagonist.tank.equipment];
|
||||
const equipmentMatrix = useTankopediaTemporary(
|
||||
(state) => state.equipmentMatrix,
|
||||
);
|
||||
const equipmentMatrix = useDuel((state) => state.protagonist!.equipment);
|
||||
|
||||
return (
|
||||
<ConfigurationChildWrapper>
|
||||
@@ -33,11 +27,12 @@ export function Equipments() {
|
||||
rowChild
|
||||
selected={equipmentMatrix[rowIndex][columnIndex] === -1}
|
||||
onClick={() => {
|
||||
mutateTankopediaTemporary((draft) => {
|
||||
mutateDuel((draft) => {
|
||||
if (equipmentMatrix[rowIndex][columnIndex] === -1) {
|
||||
draft.equipmentMatrix[rowIndex][columnIndex] = 0;
|
||||
draft.protagonist!.equipment[rowIndex][columnIndex] = 0;
|
||||
} else {
|
||||
draft.equipmentMatrix[rowIndex][columnIndex] = -1;
|
||||
draft.protagonist!.equipment[rowIndex][columnIndex] =
|
||||
-1;
|
||||
}
|
||||
});
|
||||
}}
|
||||
@@ -48,11 +43,11 @@ export function Equipments() {
|
||||
rowChild
|
||||
selected={equipmentMatrix[rowIndex][columnIndex] === 1}
|
||||
onClick={() => {
|
||||
mutateTankopediaTemporary((draft) => {
|
||||
mutateDuel((draft) => {
|
||||
if (equipmentMatrix[rowIndex][columnIndex] === 1) {
|
||||
draft.equipmentMatrix[rowIndex][columnIndex] = 0;
|
||||
draft.protagonist!.equipment[rowIndex][columnIndex] = 0;
|
||||
} else {
|
||||
draft.equipmentMatrix[rowIndex][columnIndex] = 1;
|
||||
draft.protagonist!.equipment[rowIndex][columnIndex] = 1;
|
||||
}
|
||||
});
|
||||
}}
|
||||
|
||||
+19
-18
@@ -3,19 +3,15 @@ import { clamp, debounce } from 'lodash';
|
||||
import { useEffect, useMemo, useRef, useState } from 'react';
|
||||
import { GenericTankComponentButton } from '../../../../../../../components/ModuleButtons/GenericTankComponentButton';
|
||||
import { asset } from '../../../../../../../core/blitzkrieg/asset';
|
||||
import { useDuel } from '../../../../../../../stores/duel';
|
||||
import {
|
||||
mutateTankopediaTemporary,
|
||||
useTankopediaTemporary,
|
||||
} from '../../../../../../../stores/tankopedia';
|
||||
import { mutateDuel, useDuel } from '../../../../../../../stores/duel';
|
||||
import { ConfigurationChildWrapper } from './ConfigurationChildWrapper';
|
||||
|
||||
export function Miscellaneous() {
|
||||
const camouflage = useTankopediaTemporary((state) => state.camouflage);
|
||||
const cooldownBooster = useTankopediaTemporary(
|
||||
(state) => state.cooldownBooster,
|
||||
const camouflage = useDuel((state) => state.protagonist!.camouflage);
|
||||
const cooldownBooster = useDuel(
|
||||
(state) => state.protagonist!.cooldownBooster,
|
||||
);
|
||||
const crewMastery = useTankopediaTemporary((state) => state.crewMastery);
|
||||
const crewMastery = useDuel((state) => state.protagonist!.crewMastery);
|
||||
const crewInput = useRef<HTMLInputElement>(null);
|
||||
const [crewMasteryDraft, setCrewMasteryDraft] = useState(crewMastery);
|
||||
const { tank } = useDuel((state) => state.protagonist!);
|
||||
@@ -23,8 +19,8 @@ export function Miscellaneous() {
|
||||
const debouncedApplyDraft = useMemo(
|
||||
() =>
|
||||
debounce((value) => {
|
||||
mutateTankopediaTemporary((draft) => {
|
||||
draft.crewMastery = value;
|
||||
mutateDuel((draft) => {
|
||||
draft.protagonist!.crewMastery = value;
|
||||
});
|
||||
}, 500),
|
||||
[],
|
||||
@@ -53,8 +49,8 @@ export function Miscellaneous() {
|
||||
first
|
||||
last
|
||||
onClick={() => {
|
||||
mutateTankopediaTemporary((draft) => {
|
||||
draft.camouflage = !camouflage;
|
||||
mutateDuel((draft) => {
|
||||
draft.protagonist!.camouflage = !camouflage;
|
||||
});
|
||||
}}
|
||||
/>
|
||||
@@ -77,9 +73,10 @@ export function Miscellaneous() {
|
||||
transform: 'translate(-50%, -50%) scale(0.8)',
|
||||
}}
|
||||
onClick={() => {
|
||||
mutateTankopediaTemporary((draft) => {
|
||||
draft.cooldownBooster++;
|
||||
if (draft.cooldownBooster === 4) draft.cooldownBooster = 0;
|
||||
mutateDuel((draft) => {
|
||||
draft.protagonist!.cooldownBooster++;
|
||||
if (draft.protagonist!.cooldownBooster === 4)
|
||||
draft.protagonist!.cooldownBooster = 0;
|
||||
});
|
||||
}}
|
||||
/>
|
||||
@@ -106,8 +103,12 @@ export function Miscellaneous() {
|
||||
return;
|
||||
}
|
||||
|
||||
mutateTankopediaTemporary((draft) => {
|
||||
draft.crewMastery = clamp(newValue / 100, 0.5, 1);
|
||||
mutateDuel((draft) => {
|
||||
draft.protagonist!.crewMastery = clamp(
|
||||
newValue / 100,
|
||||
0.5,
|
||||
1,
|
||||
);
|
||||
});
|
||||
}}
|
||||
onKeyUp={(event) => {
|
||||
|
||||
@@ -3,16 +3,12 @@ import { use } from 'react';
|
||||
import { ProvisionButton } from '../../../../../../../components/ModuleButtons/ProvisionButton';
|
||||
import { availableProvisions } from '../../../../../../../core/blitzkrieg/availableProvisions';
|
||||
import { provisionDefinitions } from '../../../../../../../core/blitzkrieg/provisionDefinitions';
|
||||
import { useDuel } from '../../../../../../../stores/duel';
|
||||
import {
|
||||
mutateTankopediaTemporary,
|
||||
useTankopediaTemporary,
|
||||
} from '../../../../../../../stores/tankopedia';
|
||||
import { mutateDuel, useDuel } from '../../../../../../../stores/duel';
|
||||
import { ConfigurationChildWrapper } from './ConfigurationChildWrapper';
|
||||
|
||||
export function Provisions() {
|
||||
const { tank, gun } = useDuel((state) => state.protagonist!);
|
||||
const provisions = useTankopediaTemporary((state) => state.provisions);
|
||||
const provisions = useDuel((state) => state.protagonist!.provisions);
|
||||
const awaitedProvisionDefinitions = use(provisionDefinitions);
|
||||
const provisionsList = availableProvisions(
|
||||
tank,
|
||||
@@ -38,13 +34,14 @@ export function Provisions() {
|
||||
provision={provision.id}
|
||||
selected={selected}
|
||||
onClick={() => {
|
||||
mutateTankopediaTemporary((draft) => {
|
||||
mutateDuel((draft) => {
|
||||
if (selected) {
|
||||
draft.provisions = draft.provisions.filter(
|
||||
(id) => id !== provision.id,
|
||||
);
|
||||
draft.protagonist!.provisions =
|
||||
draft.protagonist!.provisions.filter(
|
||||
(id) => id !== provision.id,
|
||||
);
|
||||
} else {
|
||||
draft.provisions.push(provision.id);
|
||||
draft.protagonist!.provisions.push(provision.id);
|
||||
}
|
||||
});
|
||||
}}
|
||||
|
||||
@@ -24,7 +24,6 @@ import { useEquipment } from '../../../../../../hooks/useEquipment';
|
||||
import { useProvision } from '../../../../../../hooks/useProvision';
|
||||
import { useProvisions } from '../../../../../../hooks/useProvisions';
|
||||
import { mutateDuel, useDuel } from '../../../../../../stores/duel';
|
||||
import { useTankopediaTemporary } from '../../../../../../stores/tankopedia';
|
||||
import { Info } from './components/Info';
|
||||
import { InfoWithDelta } from './components/InfoWithDelta';
|
||||
|
||||
@@ -35,7 +34,7 @@ export function Characteristics() {
|
||||
);
|
||||
const hasImprovedVentilation = useEquipment(102);
|
||||
const provisions = useProvisions();
|
||||
const crewMastery = useTankopediaTemporary((state) => state.crewMastery);
|
||||
const crewMastery = useDuel((state) => state.protagonist!.crewMastery);
|
||||
const provisionCrewBonus =
|
||||
provisions.reduce(
|
||||
(total, provision) =>
|
||||
@@ -67,7 +66,7 @@ export function Characteristics() {
|
||||
stockTurret.weight +
|
||||
stockGun.weight;
|
||||
const [penetrationDistance, setPenetrationDistance] = useState(250);
|
||||
const camouflage = useTankopediaTemporary((state) => state.camouflage);
|
||||
const camouflage = useDuel((state) => state.protagonist!.camouflage);
|
||||
const hasRammer = useEquipment(100);
|
||||
const hasCalibratedShells = useEquipment(103);
|
||||
const hasEnhancedGunLayingDrive = useEquipment(104);
|
||||
|
||||
@@ -11,11 +11,11 @@ import { modelTransformEvent } from '../../../../../../core/blitzkrieg/modelTran
|
||||
import { Pose, poseEvent } from '../../../../../../core/blitzkrieg/pose';
|
||||
import { tankIcon } from '../../../../../../core/blitzkrieg/tankIcon';
|
||||
import { useWideFormat } from '../../../../../../hooks/useWideFormat';
|
||||
import { useDuel } from '../../../../../../stores/duel';
|
||||
import {
|
||||
import { mutateDuel, useDuel } from '../../../../../../stores/duel';
|
||||
import mutateTankopediaPersistent, {
|
||||
TankopediaMode,
|
||||
mutateTankopediaTemporary,
|
||||
useTankopediaTemporary,
|
||||
useTankopediaPersistent,
|
||||
} from '../../../../../../stores/tankopedia';
|
||||
import { Controls } from '../Control';
|
||||
import { Lighting } from '../Lighting';
|
||||
@@ -33,7 +33,7 @@ export function TankSandbox() {
|
||||
const awaitedModelDefinitions = use(modelDefinitions);
|
||||
const canvasWrapper = useRef<HTMLDivElement>(null);
|
||||
const [isFullScreen, setIsFullScreen] = useState(false);
|
||||
const mode = useTankopediaTemporary((state) => state.mode);
|
||||
const mode = useTankopediaPersistent((state) => state.mode);
|
||||
const protagonist = useDuel((state) => state.protagonist!);
|
||||
const tankModelDefinition = awaitedModelDefinitions[protagonist.tank.id];
|
||||
const turretModelDefinition =
|
||||
@@ -65,7 +65,7 @@ export function TankSandbox() {
|
||||
function handlePoseEvent(pose: Pose) {
|
||||
switch (pose) {
|
||||
case Pose.HullDown: {
|
||||
mutateTankopediaTemporary((draft) => {
|
||||
mutateDuel((draft) => {
|
||||
const [pitch, yaw] = applyPitchYawLimits(
|
||||
-Infinity,
|
||||
0,
|
||||
@@ -74,15 +74,15 @@ export function TankSandbox() {
|
||||
);
|
||||
|
||||
modelTransformEvent.emit({ pitch, yaw });
|
||||
draft.model.pose.pitch = pitch;
|
||||
draft.model.pose.yaw = yaw;
|
||||
draft.protagonist!.pitch = pitch;
|
||||
draft.protagonist!.yaw = yaw;
|
||||
});
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case Pose.FaceHug: {
|
||||
mutateTankopediaTemporary((draft) => {
|
||||
mutateDuel((draft) => {
|
||||
const [pitch, yaw] = applyPitchYawLimits(
|
||||
Infinity,
|
||||
0,
|
||||
@@ -91,15 +91,15 @@ export function TankSandbox() {
|
||||
);
|
||||
|
||||
modelTransformEvent.emit({ pitch, yaw });
|
||||
draft.model.pose.pitch = pitch;
|
||||
draft.model.pose.yaw = yaw;
|
||||
draft.protagonist!.pitch = pitch;
|
||||
draft.protagonist!.yaw = yaw;
|
||||
});
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case Pose.Default:
|
||||
mutateTankopediaTemporary((draft) => {
|
||||
mutateDuel((draft) => {
|
||||
const [pitch, yaw] = applyPitchYawLimits(
|
||||
0,
|
||||
0,
|
||||
@@ -108,8 +108,8 @@ export function TankSandbox() {
|
||||
);
|
||||
|
||||
modelTransformEvent.emit({ pitch, yaw });
|
||||
draft.model.pose.pitch = pitch;
|
||||
draft.model.pose.yaw = yaw;
|
||||
draft.protagonist!.pitch = pitch;
|
||||
draft.protagonist!.yaw = yaw;
|
||||
});
|
||||
|
||||
break;
|
||||
@@ -126,10 +126,10 @@ export function TankSandbox() {
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
mutateTankopediaTemporary((draft) => {
|
||||
[draft.model.pose.pitch, draft.model.pose.yaw] = applyPitchYawLimits(
|
||||
draft.model.pose.pitch,
|
||||
draft.model.pose.yaw,
|
||||
mutateDuel((draft) => {
|
||||
[draft.protagonist!.pitch, draft.protagonist!.yaw] = applyPitchYawLimits(
|
||||
draft.protagonist!.pitch,
|
||||
draft.protagonist!.yaw,
|
||||
gunModelDefinition.pitch,
|
||||
turretModelDefinition.yaw,
|
||||
);
|
||||
@@ -157,7 +157,7 @@ export function TankSandbox() {
|
||||
<Tabs.Root
|
||||
value={mode}
|
||||
onValueChange={(mode) => {
|
||||
mutateTankopediaTemporary((draft) => {
|
||||
mutateTankopediaPersistent((draft) => {
|
||||
draft.mode = mode as TankopediaMode;
|
||||
});
|
||||
}}
|
||||
|
||||
+4
-4
@@ -12,7 +12,7 @@ import { resolveArmor } from '../../../../../../../../../core/blitzkrieg/resolve
|
||||
import { useArmor } from '../../../../../../../../../hooks/useArmor';
|
||||
import { useModelDefinitions } from '../../../../../../../../../hooks/useModelDefinitions';
|
||||
import { useDuel } from '../../../../../../../../../stores/duel';
|
||||
import { useTankopediaTemporary } from '../../../../../../../../../stores/tankopedia';
|
||||
import { useTankopediaPersistent } from '../../../../../../../../../stores/tankopedia';
|
||||
|
||||
export function ArmorHighlighting() {
|
||||
const protagonist = useDuel((state) => state.protagonist!);
|
||||
@@ -20,7 +20,7 @@ export function ArmorHighlighting() {
|
||||
const modelDefinitions = useModelDefinitions();
|
||||
const gunContainer = useRef<Group>(null);
|
||||
const turretContainer = useRef<Group>(null);
|
||||
const initialTankopediaState = useTankopediaTemporary.getState();
|
||||
const initialTankopediaState = useTankopediaPersistent.getState();
|
||||
|
||||
useEffect(() => {
|
||||
const hullOrigin = new Vector3(
|
||||
@@ -80,14 +80,14 @@ export function ArmorHighlighting() {
|
||||
turretContainer.current?.position.copy(turretPosition);
|
||||
turretContainer.current?.rotation.copy(turretRotation);
|
||||
}
|
||||
const unsubscribe = useTankopediaTemporary.subscribe(
|
||||
const unsubscribe = useTankopediaPersistent.subscribe(
|
||||
(state) => state.mode,
|
||||
(mode) => {
|
||||
if (wrapper.current) wrapper.current.visible = mode === 'armor';
|
||||
},
|
||||
);
|
||||
|
||||
handleModelTransform(useTankopediaTemporary.getState().model.pose);
|
||||
handleModelTransform(useDuel.getState().protagonist!);
|
||||
modelTransformEvent.on(handleModelTransform);
|
||||
|
||||
return () => {
|
||||
|
||||
+4
-4
@@ -13,7 +13,7 @@ import { useArmor } from '../../../../../../../../../hooks/useArmor';
|
||||
import { useModel } from '../../../../../../../../../hooks/useModel';
|
||||
import { useModelDefinitions } from '../../../../../../../../../hooks/useModelDefinitions';
|
||||
import { useDuel } from '../../../../../../../../../stores/duel';
|
||||
import { useTankopediaTemporary } from '../../../../../../../../../stores/tankopedia';
|
||||
import { useTankopediaPersistent } from '../../../../../../../../../stores/tankopedia';
|
||||
|
||||
interface ExternalModuleMaskProps {
|
||||
ornamental?: boolean;
|
||||
@@ -33,7 +33,7 @@ export const ExternalModuleMask = memo<ExternalModuleMaskProps>(
|
||||
const modelDefinitions = useModelDefinitions();
|
||||
const turretContainer = useRef<Group>(null);
|
||||
const gunContainer = useRef<Group>(null);
|
||||
const initialTankopediaState = useTankopediaTemporary.getState();
|
||||
const initialTankopediaState = useTankopediaPersistent.getState();
|
||||
|
||||
useEffect(() => {
|
||||
const hullOrigin = new Vector3(
|
||||
@@ -102,7 +102,7 @@ export const ExternalModuleMask = memo<ExternalModuleMaskProps>(
|
||||
turretContainer.current?.rotation.copy(turretRotation);
|
||||
}
|
||||
|
||||
handleModelTransform(useTankopediaTemporary.getState().model.pose);
|
||||
handleModelTransform(useDuel.getState().protagonist!);
|
||||
modelTransformEvent.on(handleModelTransform);
|
||||
|
||||
return () => {
|
||||
@@ -111,7 +111,7 @@ export const ExternalModuleMask = memo<ExternalModuleMaskProps>(
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
const unsubscribe = useTankopediaTemporary.subscribe(
|
||||
const unsubscribe = useTankopediaPersistent.subscribe(
|
||||
(state) => state.mode,
|
||||
(mode) => {
|
||||
if (wrapper.current) wrapper.current.visible = mode === 'armor';
|
||||
|
||||
+4
-4
@@ -13,7 +13,7 @@ import { useArmor } from '../../../../../../../../../hooks/useArmor';
|
||||
import { useModel } from '../../../../../../../../../hooks/useModel';
|
||||
import { useModelDefinitions } from '../../../../../../../../../hooks/useModelDefinitions';
|
||||
import { useDuel } from '../../../../../../../../../stores/duel';
|
||||
import { useTankopediaTemporary } from '../../../../../../../../../stores/tankopedia';
|
||||
import { useTankopediaPersistent } from '../../../../../../../../../stores/tankopedia';
|
||||
|
||||
interface SpacedArmorDepthProps {
|
||||
ornamental?: boolean;
|
||||
@@ -37,7 +37,7 @@ export const SpacedArmorDepth = memo<SpacedArmorDepthProps>(
|
||||
const modelDefinitions = useModelDefinitions();
|
||||
const turretContainer = useRef<Group>(null);
|
||||
const gunContainer = useRef<Group>(null);
|
||||
const initialTankopediaState = useTankopediaTemporary.getState();
|
||||
const initialTankopediaState = useTankopediaPersistent.getState();
|
||||
|
||||
useEffect(() => {
|
||||
if (!modelDefinitions) return;
|
||||
@@ -108,7 +108,7 @@ export const SpacedArmorDepth = memo<SpacedArmorDepthProps>(
|
||||
turretContainer.current?.rotation.copy(turretRotation);
|
||||
}
|
||||
|
||||
handleModelTransform(useTankopediaTemporary.getState().model.pose);
|
||||
handleModelTransform(useDuel.getState().protagonist!);
|
||||
modelTransformEvent.on(handleModelTransform);
|
||||
|
||||
return () => {
|
||||
@@ -117,7 +117,7 @@ export const SpacedArmorDepth = memo<SpacedArmorDepthProps>(
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
const unsubscribe = useTankopediaTemporary.subscribe(
|
||||
const unsubscribe = useTankopediaPersistent.subscribe(
|
||||
(state) => state.mode,
|
||||
(mode) => {
|
||||
if (wrapper.current) wrapper.current.visible = mode === 'armor';
|
||||
|
||||
@@ -15,10 +15,9 @@ import {
|
||||
} from '../../../../../../../core/blitzkrieg/modelTransform';
|
||||
import { normalizeAnglePI } from '../../../../../../../core/math/normalizeAngle180';
|
||||
import { useModel } from '../../../../../../../hooks/useModel';
|
||||
import { useDuel } from '../../../../../../../stores/duel';
|
||||
import { mutateDuel, useDuel } from '../../../../../../../stores/duel';
|
||||
import mutateTankopediaPersistent, {
|
||||
mutateTankopediaTemporary,
|
||||
useTankopediaTemporary,
|
||||
} from '../../../../../../../stores/tankopedia';
|
||||
|
||||
export const TankModel = memo(() => {
|
||||
@@ -27,7 +26,6 @@ export const TankModel = memo(() => {
|
||||
>(undefined);
|
||||
const protagonist = useDuel((draft) => draft.protagonist!);
|
||||
const canvas = useThree((state) => state.gl.domElement);
|
||||
const physical = useTankopediaTemporary((state) => state.model.pose);
|
||||
const hullContainer = useRef<Group>(null);
|
||||
const turretContainer = useRef<Group>(null);
|
||||
const gunContainer = useRef<Group>(null);
|
||||
@@ -156,8 +154,8 @@ export const TankModel = memo(() => {
|
||||
event.stopPropagation();
|
||||
|
||||
if (isTurret) {
|
||||
yaw = physical.yaw;
|
||||
pitch = physical.pitch;
|
||||
yaw = protagonist.yaw;
|
||||
pitch = protagonist.pitch;
|
||||
|
||||
mutateTankopediaPersistent((draft) => {
|
||||
draft.model.visual.controlsEnabled = false;
|
||||
@@ -179,9 +177,9 @@ export const TankModel = memo(() => {
|
||||
modelTransformEvent.emit({ pitch, yaw });
|
||||
}
|
||||
function handlePointerUp() {
|
||||
mutateTankopediaTemporary((draft) => {
|
||||
draft.model.pose.pitch = normalizeAnglePI(pitch);
|
||||
draft.model.pose.yaw = normalizeAnglePI(yaw);
|
||||
mutateDuel((draft) => {
|
||||
draft.protagonist!.pitch = normalizeAnglePI(pitch);
|
||||
draft.protagonist!.yaw = normalizeAnglePI(yaw);
|
||||
});
|
||||
mutateTankopediaPersistent((draft) => {
|
||||
draft.model.visual.controlsEnabled = true;
|
||||
@@ -223,8 +221,8 @@ export const TankModel = memo(() => {
|
||||
mutateTankopediaTemporary((draft) => {
|
||||
draft.shot = undefined;
|
||||
});
|
||||
pitch = physical.pitch;
|
||||
yaw = physical.yaw;
|
||||
pitch = protagonist.pitch;
|
||||
yaw = protagonist.yaw;
|
||||
window.addEventListener('pointermove', handlePointerMove);
|
||||
window.addEventListener('pointerup', handlePointerUp);
|
||||
}
|
||||
@@ -241,9 +239,9 @@ export const TankModel = memo(() => {
|
||||
mutateTankopediaPersistent((draft) => {
|
||||
draft.model.visual.controlsEnabled = true;
|
||||
});
|
||||
mutateTankopediaTemporary((draft) => {
|
||||
draft.model.pose.pitch = normalizeAnglePI(pitch);
|
||||
draft.model.pose.yaw = normalizeAnglePI(yaw);
|
||||
mutateDuel((draft) => {
|
||||
draft.protagonist!.pitch = normalizeAnglePI(pitch);
|
||||
draft.protagonist!.yaw = normalizeAnglePI(yaw);
|
||||
});
|
||||
window.removeEventListener('pointermove', handlePointerMove);
|
||||
window.removeEventListener('pointerup', handlePointerUp);
|
||||
|
||||
@@ -4,33 +4,29 @@ import { applyPitchYawLimits } from '../../../../../../core/blitz/applyPitchYawL
|
||||
import { modelDefinitions } from '../../../../../../core/blitzkrieg/modelDefinitions';
|
||||
import { modelTransformEvent } from '../../../../../../core/blitzkrieg/modelTransform';
|
||||
import { useEquipment } from '../../../../../../hooks/useEquipment';
|
||||
import { useDuel } from '../../../../../../stores/duel';
|
||||
import {
|
||||
mutateTankopediaTemporary,
|
||||
useTankopediaTemporary,
|
||||
} from '../../../../../../stores/tankopedia';
|
||||
import { mutateDuel, useDuel } from '../../../../../../stores/duel';
|
||||
import { useTankopediaPersistent } from '../../../../../../stores/tankopedia';
|
||||
import { QuickEquipmentButton } from './components/QuickEquipmentButton';
|
||||
|
||||
export function RotationInputs() {
|
||||
const protagonist = useDuel((state) => state.protagonist!);
|
||||
const physical = useTankopediaTemporary((state) => state.model.pose);
|
||||
const awaitedModelDefinitions = use(modelDefinitions);
|
||||
const turretYawInput = useRef<HTMLInputElement>(null);
|
||||
const gunPitchInput = useRef<HTMLInputElement>(null);
|
||||
const mode = useTankopediaTemporary((state) => state.mode);
|
||||
const hasCalibratedShells = useEquipment(103);
|
||||
const mode = useTankopediaPersistent((state) => state.mode);
|
||||
const hasCalibratedShells = useEquipment(103, true);
|
||||
const hasEnhancedArmor = useEquipment(110);
|
||||
|
||||
useEffect(() => {
|
||||
turretYawInput.current!.value = `${-Math.round(
|
||||
physical.yaw * (180 / Math.PI),
|
||||
protagonist.yaw * (180 / Math.PI),
|
||||
)}`;
|
||||
}, [physical.yaw]);
|
||||
}, [protagonist.yaw]);
|
||||
useEffect(() => {
|
||||
gunPitchInput.current!.value = `${-Math.round(
|
||||
physical.pitch * (180 / Math.PI),
|
||||
protagonist.pitch * (180 / Math.PI),
|
||||
)}`;
|
||||
}, [physical.pitch]);
|
||||
}, [protagonist.pitch]);
|
||||
|
||||
const tankModelDefinition = awaitedModelDefinitions[protagonist.tank.id];
|
||||
const turretModelDefinition =
|
||||
@@ -68,18 +64,18 @@ export function RotationInputs() {
|
||||
Yaw
|
||||
</TextField.Slot>
|
||||
<TextField.Input
|
||||
defaultValue={Math.round(physical.yaw * (180 / Math.PI))}
|
||||
defaultValue={Math.round(protagonist.yaw * (180 / Math.PI))}
|
||||
onBlur={() => {
|
||||
const [pitch, yaw] = applyPitchYawLimits(
|
||||
physical.pitch,
|
||||
protagonist.pitch,
|
||||
-Number(turretYawInput.current?.value) * (Math.PI / 180),
|
||||
gunModelDefinition.pitch,
|
||||
turretModelDefinition.yaw,
|
||||
);
|
||||
modelTransformEvent.emit({ pitch, yaw });
|
||||
mutateTankopediaTemporary((state) => {
|
||||
state.model.pose.pitch = pitch;
|
||||
state.model.pose.yaw = yaw;
|
||||
useDuel((state) => {
|
||||
state.protagonist!.pitch = pitch;
|
||||
state.protagonist!.yaw = yaw;
|
||||
});
|
||||
turretYawInput.current!.value = `${Math.round(
|
||||
yaw * (180 / Math.PI),
|
||||
@@ -116,18 +112,18 @@ export function RotationInputs() {
|
||||
Pitch
|
||||
</TextField.Slot>
|
||||
<TextField.Input
|
||||
defaultValue={-Math.round(physical.pitch * (180 / Math.PI))}
|
||||
defaultValue={-Math.round(protagonist.pitch * (180 / Math.PI))}
|
||||
onBlur={() => {
|
||||
const [pitch, yaw] = applyPitchYawLimits(
|
||||
-Number(gunPitchInput.current?.value) * (Math.PI / 180),
|
||||
physical.yaw,
|
||||
protagonist.yaw,
|
||||
gunModelDefinition.pitch,
|
||||
turretModelDefinition.yaw,
|
||||
);
|
||||
modelTransformEvent.emit({ pitch, yaw });
|
||||
mutateTankopediaTemporary((state) => {
|
||||
state.model.pose.pitch = pitch;
|
||||
state.model.pose.yaw = yaw;
|
||||
mutateDuel((state) => {
|
||||
state.protagonist!.pitch = pitch;
|
||||
state.protagonist!.yaw = yaw;
|
||||
});
|
||||
gunPitchInput.current!.value = `${Math.round(
|
||||
pitch * (180 / Math.PI),
|
||||
@@ -158,8 +154,8 @@ export function RotationInputs() {
|
||||
equipment={103}
|
||||
active={hasCalibratedShells}
|
||||
onClick={() => {
|
||||
mutateTankopediaTemporary((draft) => {
|
||||
draft.equipmentMatrix[0][0] = hasCalibratedShells ? 0 : 1;
|
||||
mutateDuel((draft) => {
|
||||
draft.antagonist!.equipment[0][0] = hasCalibratedShells ? 0 : 1;
|
||||
});
|
||||
}}
|
||||
/>
|
||||
@@ -167,8 +163,8 @@ export function RotationInputs() {
|
||||
equipment={110}
|
||||
active={hasEnhancedArmor}
|
||||
onClick={() => {
|
||||
mutateTankopediaTemporary((draft) => {
|
||||
draft.equipmentMatrix[1][1] = hasEnhancedArmor ? 0 : -1;
|
||||
mutateDuel((draft) => {
|
||||
draft.protagonist!.equipment[1][1] = hasEnhancedArmor ? 0 : -1;
|
||||
});
|
||||
}}
|
||||
/>
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
'use client';
|
||||
|
||||
import { Flex } from '@radix-ui/themes';
|
||||
import { use, useEffect } from 'react';
|
||||
import { useEffect } from 'react';
|
||||
import PageWrapper from '../../../../components/PageWrapper';
|
||||
import { availableProvisions } from '../../../../core/blitzkrieg/availableProvisions';
|
||||
import { provisionDefinitions } from '../../../../core/blitzkrieg/provisionDefinitions';
|
||||
import { tankDefinitions } from '../../../../core/blitzkrieg/tankDefinitions';
|
||||
import { assignDuelMember } from '../../../../core/blitzkrieg/assignDuelMember';
|
||||
import { useWideFormat } from '../../../../hooks/useWideFormat';
|
||||
import { mutateDuel, useDuel } from '../../../../stores/duel';
|
||||
import { mutateTankopediaTemporary } from '../../../../stores/tankopedia';
|
||||
@@ -20,26 +18,12 @@ import { TankSandbox } from './components/Model/TankSandbox';
|
||||
import { Title } from './components/Title';
|
||||
|
||||
export default function Page({ params }: { params: { id: string } }) {
|
||||
const id = parseInt(params.id);
|
||||
const awaitedTankDefinitions = use(tankDefinitions);
|
||||
const tank = awaitedTankDefinitions[id];
|
||||
const gun = tank.turrets.at(-1)!.guns.at(-1)!;
|
||||
const initialId = parseInt(params.id);
|
||||
const assigned = useDuel((state) => state.assigned);
|
||||
const wideFormat = useWideFormat();
|
||||
|
||||
useEffect(() => {
|
||||
mutateDuel((draft) => {
|
||||
draft.assigned = true;
|
||||
draft.protagonist = {
|
||||
tank,
|
||||
engine: tank.engines.at(-1)!,
|
||||
turret: tank.turrets.at(-1)!,
|
||||
gun,
|
||||
shell: tank.turrets.at(-1)!.guns.at(-1)!.shells[0],
|
||||
track: tank.tracks.at(-1)!,
|
||||
};
|
||||
draft.antagonist = { ...draft.protagonist };
|
||||
});
|
||||
assignDuelMember('both', initialId);
|
||||
|
||||
function handleKeyDown(event: KeyboardEvent) {
|
||||
if (document.activeElement instanceof HTMLInputElement) return;
|
||||
@@ -72,34 +56,12 @@ export default function Page({ params }: { params: { id: string } }) {
|
||||
}
|
||||
}
|
||||
|
||||
(async () => {
|
||||
const provisionsList = availableProvisions(
|
||||
tank,
|
||||
gun,
|
||||
await provisionDefinitions,
|
||||
);
|
||||
mutateTankopediaTemporary((draft) => {
|
||||
draft.model.pose.yaw = 0;
|
||||
draft.model.pose.pitch = 0;
|
||||
draft.consumables = [];
|
||||
draft.provisions = provisionsList
|
||||
.filter((provision) => provision.crew !== undefined)
|
||||
.map((provision) => provision.id);
|
||||
draft.shot = undefined;
|
||||
draft.equipmentMatrix = [
|
||||
[1, -1, -1],
|
||||
[0, 0, 0],
|
||||
[0, 0, 0],
|
||||
];
|
||||
});
|
||||
})();
|
||||
|
||||
window.addEventListener('keydown', handleKeyDown);
|
||||
|
||||
return () => {
|
||||
window.removeEventListener('keydown', handleKeyDown);
|
||||
};
|
||||
}, [id, assigned]);
|
||||
}, [initialId, assigned]);
|
||||
|
||||
return (
|
||||
<PageWrapper color="purple" size="double">
|
||||
|
||||
@@ -22,7 +22,6 @@ import {
|
||||
Shot,
|
||||
mutateTankopediaTemporary,
|
||||
useTankopediaPersistent,
|
||||
useTankopediaTemporary,
|
||||
} from '../../../../stores/tankopedia';
|
||||
import { externalModuleMaskRenderTarget } from '../ExternalModuleMask';
|
||||
import { spacedArmorDepthRenderTarget } from '../SpacedArmorDepth';
|
||||
@@ -52,7 +51,7 @@ export const ArmorMesh = memo<ArmorMeshProps>(
|
||||
const surfaceNormal = new Vector3();
|
||||
const mesh = useRef<Mesh>(null);
|
||||
const scene = useThree((state) => state.scene);
|
||||
const hasCalibratedShells = useAwait(hasEquipment(103));
|
||||
const hasCalibratedShells = useAwait(hasEquipment(103, true));
|
||||
const hasEnhancedArmor = useAwait(hasEquipment(110));
|
||||
const wireframe = initialTankopedia.model.visual.wireframe;
|
||||
|
||||
@@ -92,8 +91,8 @@ export const ArmorMesh = memo<ArmorMeshProps>(
|
||||
}
|
||||
|
||||
const unsubscribes = [
|
||||
useTankopediaTemporary.subscribe(
|
||||
(state) => state.equipmentMatrix,
|
||||
useDuel.subscribe(
|
||||
(state) => state.protagonist!.equipment,
|
||||
updateQuickEquipments,
|
||||
),
|
||||
useDuel.subscribe(
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
import {
|
||||
DuelMember,
|
||||
genericDefaultEquipmentMatrix,
|
||||
mutateDuel,
|
||||
} from '../../stores/duel';
|
||||
import { availableProvisions } from './availableProvisions';
|
||||
import { provisionDefinitions } from './provisionDefinitions';
|
||||
import { tankDefinitions } from './tankDefinitions';
|
||||
|
||||
export async function assignDuelMember(
|
||||
type: 'antagonist' | 'protagonist' | 'both',
|
||||
id: number,
|
||||
) {
|
||||
const awaitedTankDefinitions = await tankDefinitions;
|
||||
const awaitedProvisionDefinitions = await provisionDefinitions;
|
||||
const tank = awaitedTankDefinitions[id];
|
||||
const turret = tank.turrets.at(-1)!;
|
||||
const gun = turret.guns.at(-1)!;
|
||||
const shell = gun.shells[0];
|
||||
const engine = tank.engines.at(-1)!;
|
||||
const track = tank.tracks.at(-1)!;
|
||||
const provisionsList = availableProvisions(
|
||||
tank,
|
||||
gun,
|
||||
awaitedProvisionDefinitions,
|
||||
);
|
||||
const member: DuelMember = {
|
||||
tank,
|
||||
engine,
|
||||
turret,
|
||||
gun,
|
||||
shell,
|
||||
track,
|
||||
equipment: genericDefaultEquipmentMatrix,
|
||||
pitch: 0,
|
||||
yaw: 0,
|
||||
camouflage: true,
|
||||
consumables: [],
|
||||
cooldownBooster: 0,
|
||||
crewMastery: 1,
|
||||
provisions: provisionsList
|
||||
.filter((provision) => provision.crew !== undefined)
|
||||
.map((provision) => provision.id),
|
||||
};
|
||||
|
||||
mutateDuel((draft) => {
|
||||
draft.assigned = true;
|
||||
if (type === 'antagonist') {
|
||||
draft.antagonist = member;
|
||||
} else if (type === 'protagonist') {
|
||||
draft.protagonist = member;
|
||||
} else {
|
||||
draft.protagonist = member;
|
||||
draft.antagonist = { ...member };
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -1,13 +1,13 @@
|
||||
import { useDuel } from '../../stores/duel';
|
||||
import { useTankopediaTemporary } from '../../stores/tankopedia';
|
||||
import { equipmentDefinitions } from './equipmentDefinitions';
|
||||
|
||||
export async function hasEquipment(id: number) {
|
||||
export async function hasEquipment(id: number, antagonist = false) {
|
||||
const awaitedEquipmentDefinitions = await equipmentDefinitions;
|
||||
const protagonist = useDuel.getState().protagonist!;
|
||||
const member = useDuel.getState()[antagonist ? 'antagonist' : 'protagonist']!;
|
||||
const equipmentRows =
|
||||
awaitedEquipmentDefinitions.presets[protagonist.tank.equipment];
|
||||
const equipmentMatrix = useTankopediaTemporary.getState().equipmentMatrix;
|
||||
awaitedEquipmentDefinitions.presets[member.tank.equipment];
|
||||
const equipmentMatrix =
|
||||
useDuel.getState()[antagonist ? 'antagonist' : 'protagonist']!.equipment;
|
||||
|
||||
return equipmentRows.some((equipmentRow, rowIndex) => {
|
||||
return equipmentRow.some((equipment, columnIndex) => {
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
import { EquipmentPreset } from '../core/blitzkrieg/equipmentDefinitions';
|
||||
import { EquipmentMatrix } from '../stores/tankopedia';
|
||||
import { EquipmentMatrix } from '../stores/duel';
|
||||
|
||||
export function useAppliedEquipments(
|
||||
matrix: EquipmentMatrix,
|
||||
preset: EquipmentPreset,
|
||||
) {
|
||||
const flatMatrix = matrix.flat();
|
||||
return preset.flat().map((options, index) => options[flatMatrix[index] == 1 ? 1 : 0]);
|
||||
return preset
|
||||
.flat()
|
||||
.map((options, index) => options[flatMatrix[index] == 1 ? 1 : 0]);
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
import { useTankopediaTemporary } from '../stores/tankopedia';
|
||||
import { useDuel } from '../stores/duel';
|
||||
|
||||
export function useConsumable(id: number) {
|
||||
const consumables = useTankopediaTemporary((state) => state.consumables);
|
||||
const consumables = useDuel((state) => state.protagonist!.consumables);
|
||||
return consumables.includes(id);
|
||||
}
|
||||
@@ -1,15 +1,16 @@
|
||||
import { use, useMemo } from 'react';
|
||||
import { equipmentDefinitions } from '../core/blitzkrieg/equipmentDefinitions';
|
||||
import { useDuel } from '../stores/duel';
|
||||
import { useTankopediaTemporary } from '../stores/tankopedia';
|
||||
|
||||
export function useEquipment(id: number) {
|
||||
export function useEquipment(id: number, antagonist = false) {
|
||||
const awaitedEquipmentDefinitions = use(equipmentDefinitions);
|
||||
const protagonist = useDuel((state) => state.protagonist!);
|
||||
const member = useDuel(
|
||||
(state) => state[antagonist ? 'antagonist' : 'protagonist']!,
|
||||
);
|
||||
const equipmentRows =
|
||||
awaitedEquipmentDefinitions.presets[protagonist.tank.equipment];
|
||||
const equipmentMatrix = useTankopediaTemporary(
|
||||
(state) => state.equipmentMatrix,
|
||||
awaitedEquipmentDefinitions.presets[member.tank.equipment];
|
||||
const equipmentMatrix = useDuel(
|
||||
(state) => state[antagonist ? 'antagonist' : 'protagonist']!.equipment,
|
||||
);
|
||||
const value = useMemo(
|
||||
() =>
|
||||
@@ -21,7 +22,7 @@ export function useEquipment(id: number) {
|
||||
return equipped === id;
|
||||
});
|
||||
}),
|
||||
[equipmentMatrix, protagonist.tank],
|
||||
[equipmentMatrix, member.tank],
|
||||
);
|
||||
|
||||
return value;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { useTankopediaTemporary } from '../stores/tankopedia';
|
||||
import { useDuel } from '../stores/duel';
|
||||
|
||||
export function useProvision(id: number) {
|
||||
const provisions = useTankopediaTemporary((state) => state.provisions);
|
||||
const provisions = useDuel((state) => state.protagonist!.provisions);
|
||||
return provisions.includes(id);
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
import { use } from 'react';
|
||||
import { provisionDefinitions } from '../core/blitzkrieg/provisionDefinitions';
|
||||
import { useTankopediaTemporary } from '../stores/tankopedia';
|
||||
import { useDuel } from '../stores/duel';
|
||||
|
||||
export function useProvisions() {
|
||||
const provisions = useTankopediaTemporary((state) => state.provisions);
|
||||
const provisions = useDuel((state) => state.protagonist!.provisions);
|
||||
const awaitedProvisionDefinitions = use(provisionDefinitions);
|
||||
return provisions.map((id) => awaitedProvisionDefinitions[id]);
|
||||
}
|
||||
+43
-1
@@ -1,7 +1,43 @@
|
||||
import { produce } from 'immer';
|
||||
import { create } from 'zustand';
|
||||
import { subscribeWithSelector } from 'zustand/middleware';
|
||||
import { DuelMember } from './tankopedia';
|
||||
import {
|
||||
EngineDefinition,
|
||||
GunDefinition,
|
||||
ShellDefinition,
|
||||
TankDefinition,
|
||||
TrackDefinition,
|
||||
TurretDefinition,
|
||||
} from '../core/blitzkrieg/tankDefinitions';
|
||||
|
||||
type EquipmentMatrixItem = -1 | 0 | 1;
|
||||
type EquipmentMatrixRow = [
|
||||
EquipmentMatrixItem,
|
||||
EquipmentMatrixItem,
|
||||
EquipmentMatrixItem,
|
||||
];
|
||||
export type EquipmentMatrix = [
|
||||
EquipmentMatrixRow,
|
||||
EquipmentMatrixRow,
|
||||
EquipmentMatrixRow,
|
||||
];
|
||||
|
||||
export interface DuelMember {
|
||||
tank: TankDefinition;
|
||||
engine: EngineDefinition;
|
||||
turret: TurretDefinition;
|
||||
gun: GunDefinition;
|
||||
shell: ShellDefinition;
|
||||
track: TrackDefinition;
|
||||
equipment: EquipmentMatrix;
|
||||
pitch: number;
|
||||
yaw: number;
|
||||
consumables: number[];
|
||||
crewMastery: number;
|
||||
provisions: number[];
|
||||
camouflage: boolean;
|
||||
cooldownBooster: number;
|
||||
}
|
||||
|
||||
export interface Duel {
|
||||
assigned: boolean;
|
||||
@@ -18,3 +54,9 @@ export const useDuel = create<Duel>()(
|
||||
export function mutateDuel(recipe: (draft: Duel) => void) {
|
||||
useDuel.setState(produce(recipe));
|
||||
}
|
||||
|
||||
export const genericDefaultEquipmentMatrix: EquipmentMatrix = [
|
||||
[1, 1, -1],
|
||||
[0, 0, 0],
|
||||
[0, 0, 0],
|
||||
];
|
||||
@@ -5,28 +5,13 @@ import { create } from 'zustand';
|
||||
import { persist, subscribeWithSelector } from 'zustand/middleware';
|
||||
import { ENVIRONMENTS } from '../app/tools/tankopedia/[id]/components/Lighting';
|
||||
import { TankType, TreeType } from '../components/Tanks';
|
||||
import {
|
||||
EngineDefinition,
|
||||
GunDefinition,
|
||||
ShellDefinition,
|
||||
TankDefinition,
|
||||
Tier,
|
||||
TrackDefinition,
|
||||
TurretDefinition,
|
||||
} from '../core/blitzkrieg/tankDefinitions';
|
||||
import { Tier } from '../core/blitzkrieg/tankDefinitions';
|
||||
|
||||
export type TankopediaSortBy = keyof typeof SORT_NAMES;
|
||||
export type TankopediaSortDirection = 'ascending' | 'descending';
|
||||
export type TankopediaTestTankDisplay = 'include' | 'exclude' | 'only';
|
||||
export type TankopediaMode = 'model' | 'armor';
|
||||
export interface DuelMember {
|
||||
tank: TankDefinition;
|
||||
engine: EngineDefinition;
|
||||
turret: TurretDefinition;
|
||||
gun: GunDefinition;
|
||||
shell: ShellDefinition;
|
||||
track: TrackDefinition;
|
||||
}
|
||||
|
||||
interface TankopediaPersistent {
|
||||
model: {
|
||||
visual: {
|
||||
@@ -50,24 +35,10 @@ interface TankopediaPersistent {
|
||||
test: TankopediaTestTankDisplay;
|
||||
page: number;
|
||||
};
|
||||
mode: TankopediaMode;
|
||||
}
|
||||
|
||||
export type EquipmentMatrix = (-1 | 0 | 1)[][];
|
||||
|
||||
interface TankopediaTemporary {
|
||||
model: {
|
||||
pose: {
|
||||
yaw: number;
|
||||
pitch: number;
|
||||
};
|
||||
};
|
||||
equipmentMatrix: EquipmentMatrix;
|
||||
mode: TankopediaMode;
|
||||
consumables: number[];
|
||||
crewMastery: number;
|
||||
provisions: number[];
|
||||
camouflage: boolean;
|
||||
cooldownBooster: number;
|
||||
shot?: Shot;
|
||||
}
|
||||
|
||||
@@ -152,31 +123,14 @@ export const useTankopediaPersistent = create<TankopediaPersistent>()(
|
||||
test: 'include',
|
||||
page: 0,
|
||||
},
|
||||
mode: 'model',
|
||||
})),
|
||||
{ name: 'tankopedia', merge },
|
||||
),
|
||||
);
|
||||
|
||||
export const useTankopediaTemporary = create<TankopediaTemporary>()(
|
||||
subscribeWithSelector<TankopediaTemporary>(() => ({
|
||||
model: {
|
||||
pose: {
|
||||
yaw: 0,
|
||||
pitch: 0,
|
||||
},
|
||||
},
|
||||
equipmentMatrix: [
|
||||
[0, 0, 0],
|
||||
[0, 0, 0],
|
||||
[0, 0, 0],
|
||||
],
|
||||
crewMastery: 1,
|
||||
mode: 'model',
|
||||
consumables: [],
|
||||
provisions: [],
|
||||
camouflage: true,
|
||||
cooldownBooster: 0,
|
||||
})),
|
||||
subscribeWithSelector<TankopediaTemporary>(() => ({})),
|
||||
);
|
||||
|
||||
export default function mutateTankopediaPersistent(
|
||||
|
||||
Reference in new issue
Block a user