mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-24 12:09:51 +02:00
feat: provisions
This commit is contained in:
1 parent
561b59d235
commit
5bbe93bcec
14 files changed
+220
-40
No files matched your search
@@ -4,7 +4,7 @@ import { commitAssets } from '../../src/core/blitzkrieg/commitAssets';
|
|||||||
import { FileChange } from '../../src/core/blitzkrieg/commitMultipleFiles';
|
import { FileChange } from '../../src/core/blitzkrieg/commitMultipleFiles';
|
||||||
import { DATA, POI } from './constants';
|
import { DATA, POI } from './constants';
|
||||||
|
|
||||||
export async function buildCircleFlags(production: boolean) {
|
export async function circleFlags(production: boolean) {
|
||||||
const flags = await readdir(`${DATA}/${POI.flags}`);
|
const flags = await readdir(`${DATA}/${POI.flags}`);
|
||||||
const changes = await Promise.all(
|
const changes = await Promise.all(
|
||||||
flags
|
flags
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ export const POI = {
|
|||||||
optionalDevicesImage:
|
optionalDevicesImage:
|
||||||
'Gfx/UI/InventoryIcons/Big/OptionalDevices/texture0.packed.webp',
|
'Gfx/UI/InventoryIcons/Big/OptionalDevices/texture0.packed.webp',
|
||||||
consumablesCommon: 'XML/item_defs/vehicles/common/consumables/common.xml',
|
consumablesCommon: 'XML/item_defs/vehicles/common/consumables/common.xml',
|
||||||
|
provisionsCommon: 'XML/item_defs/vehicles/common/provisions/common.xml',
|
||||||
consumableIcons: 'Gfx/UI/InventoryIcons/Big/Consumables',
|
consumableIcons: 'Gfx/UI/InventoryIcons/Big/Consumables',
|
||||||
equipmentItemImageMappings:
|
equipmentItemImageMappings:
|
||||||
'UI/Screens3/Lobby/Inventory/Equipment/EquipmentItemImage.style.yaml',
|
'UI/Screens3/Lobby/Inventory/Equipment/EquipmentItemImage.style.yaml',
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import { readYAMLDVPL } from '../../src/core/blitz/readYAMLDVPL';
|
|||||||
import { commitAssets } from '../../src/core/blitzkrieg/commitAssets';
|
import { commitAssets } from '../../src/core/blitzkrieg/commitAssets';
|
||||||
import { FileChange } from '../../src/core/blitzkrieg/commitMultipleFiles';
|
import { FileChange } from '../../src/core/blitzkrieg/commitMultipleFiles';
|
||||||
import { DATA, POI } from './constants';
|
import { DATA, POI } from './constants';
|
||||||
import { ConsumablesCommon } from './definitions';
|
import { ConsumablesProvisionsCommon } from './definitions';
|
||||||
|
|
||||||
interface Mappings {
|
interface Mappings {
|
||||||
Header: { version: number };
|
Header: { version: number };
|
||||||
@@ -16,7 +16,7 @@ interface Mappings {
|
|||||||
}[];
|
}[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function buildConsumableIcons(production: boolean) {
|
export async function consumableIcons(production: boolean) {
|
||||||
console.log('Building consumable icons...');
|
console.log('Building consumable icons...');
|
||||||
|
|
||||||
const changes: FileChange[] = [];
|
const changes: FileChange[] = [];
|
||||||
@@ -29,9 +29,9 @@ export async function buildConsumableIcons(production: boolean) {
|
|||||||
const equipmentItemImageMappings = await readYAMLDVPL<Mappings>(
|
const equipmentItemImageMappings = await readYAMLDVPL<Mappings>(
|
||||||
`${DATA}/${POI.equipmentItemImageMappings}.dvpl`,
|
`${DATA}/${POI.equipmentItemImageMappings}.dvpl`,
|
||||||
);
|
);
|
||||||
const consumablesCommon = await readXMLDVPL<{ root: ConsumablesCommon }>(
|
const consumablesCommon = await readXMLDVPL<{
|
||||||
`${DATA}/${POI.consumablesCommon}.dvpl`,
|
root: ConsumablesProvisionsCommon;
|
||||||
);
|
}>(`${DATA}/${POI.consumablesCommon}.dvpl`);
|
||||||
const styleSheets = Object.values(equipmentItemImageMappings.StyleSheets);
|
const styleSheets = Object.values(equipmentItemImageMappings.StyleSheets);
|
||||||
|
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
|
|||||||
@@ -8,9 +8,9 @@ import { readYAMLDVPL } from '../../src/core/blitz/readYAMLDVPL';
|
|||||||
import { toUniqueId } from '../../src/core/blitz/toUniqueId';
|
import { toUniqueId } from '../../src/core/blitz/toUniqueId';
|
||||||
import { commitAssets } from '../../src/core/blitzkrieg/commitAssets';
|
import { commitAssets } from '../../src/core/blitzkrieg/commitAssets';
|
||||||
import {
|
import {
|
||||||
ConsumableDefinitionFilterCategory,
|
|
||||||
ConsumableDefinitions,
|
ConsumableDefinitions,
|
||||||
} from '../../src/core/blitzkrieg/consumablesDefinitions';
|
TankFilterDefinitionCategory,
|
||||||
|
} from '../../src/core/blitzkrieg/consumableDefinitions';
|
||||||
import {
|
import {
|
||||||
EquipmentDefinitions,
|
EquipmentDefinitions,
|
||||||
EquipmentPreset,
|
EquipmentPreset,
|
||||||
@@ -20,6 +20,7 @@ import {
|
|||||||
ModelArmor,
|
ModelArmor,
|
||||||
ModelDefinitions,
|
ModelDefinitions,
|
||||||
} from '../../src/core/blitzkrieg/modelDefinitions';
|
} from '../../src/core/blitzkrieg/modelDefinitions';
|
||||||
|
import { ProvisionDefinitions } from '../../src/core/blitzkrieg/provisionDefinitions';
|
||||||
import {
|
import {
|
||||||
GunDefinition,
|
GunDefinition,
|
||||||
ShellType,
|
ShellType,
|
||||||
@@ -61,6 +62,7 @@ type VehicleDefinitionArmor = Record<
|
|||||||
interface VehicleDefinitions {
|
interface VehicleDefinitions {
|
||||||
invisibility: { moving: number; still: number; firePenalty: number };
|
invisibility: { moving: number; still: number; firePenalty: number };
|
||||||
consumableSlots: number;
|
consumableSlots: number;
|
||||||
|
provisionSlots: number;
|
||||||
optDevicePreset: string;
|
optDevicePreset: string;
|
||||||
hull: {
|
hull: {
|
||||||
armor: VehicleDefinitionArmor;
|
armor: VehicleDefinitionArmor;
|
||||||
@@ -190,7 +192,7 @@ interface OptionalDeviceSlotRow {
|
|||||||
[key: string]: { device0: string; device1: string };
|
[key: string]: { device0: string; device1: string };
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ConsumablesCommon {
|
export interface ConsumablesProvisionsCommon {
|
||||||
[key: string]: {
|
[key: string]: {
|
||||||
id: number;
|
id: number;
|
||||||
userString: string;
|
userString: string;
|
||||||
@@ -198,7 +200,7 @@ export interface ConsumablesCommon {
|
|||||||
icon: string;
|
icon: string;
|
||||||
category: string;
|
category: string;
|
||||||
tags: string;
|
tags: string;
|
||||||
vehicleFilter: {
|
vehicleFilter?: {
|
||||||
include: { vehicle: ConsumablesFilter };
|
include: { vehicle: ConsumablesFilter };
|
||||||
exclude?: { vehicle: ConsumablesFilter };
|
exclude?: { vehicle: ConsumablesFilter };
|
||||||
};
|
};
|
||||||
@@ -218,7 +220,7 @@ type ConsumablesFilter =
|
|||||||
| { name: string }
|
| { name: string }
|
||||||
| { extendedTags: string };
|
| { extendedTags: string };
|
||||||
|
|
||||||
const consumableEffectSuffixes = [
|
const consumableProvisionEffectSuffixes = [
|
||||||
'Increase',
|
'Increase',
|
||||||
'Factor',
|
'Factor',
|
||||||
'Bias',
|
'Bias',
|
||||||
@@ -241,7 +243,7 @@ const missingStrings: Record<string, string> = {
|
|||||||
'#artefacts:tungstentip/name': 'Tungsten Shells',
|
'#artefacts:tungstentip/name': 'Tungsten Shells',
|
||||||
};
|
};
|
||||||
|
|
||||||
export async function buildDefinitions(production: boolean) {
|
export async function definitions(production: boolean) {
|
||||||
console.log('Building tank definitions...');
|
console.log('Building tank definitions...');
|
||||||
|
|
||||||
const tankDefinitions: TankDefinitions = {};
|
const tankDefinitions: TankDefinitions = {};
|
||||||
@@ -251,6 +253,7 @@ export async function buildDefinitions(production: boolean) {
|
|||||||
equipments: {},
|
equipments: {},
|
||||||
};
|
};
|
||||||
const consumableDefinitions: ConsumableDefinitions = {};
|
const consumableDefinitions: ConsumableDefinitions = {};
|
||||||
|
const provisionDefinitions: ProvisionDefinitions = {};
|
||||||
const nations = await readdir(`${DATA}/${POI.vehicleDefinitions}`).then(
|
const nations = await readdir(`${DATA}/${POI.vehicleDefinitions}`).then(
|
||||||
(nations) => nations.filter((nation) => nation !== 'common'),
|
(nations) => nations.filter((nation) => nation !== 'common'),
|
||||||
);
|
);
|
||||||
@@ -267,9 +270,12 @@ export async function buildDefinitions(production: boolean) {
|
|||||||
const optionalDeviceSlots = await readXMLDVPL<{
|
const optionalDeviceSlots = await readXMLDVPL<{
|
||||||
root: OptionalDeviceSlots;
|
root: OptionalDeviceSlots;
|
||||||
}>(`${DATA}/${POI.optionalDeviceSlots}.dvpl`);
|
}>(`${DATA}/${POI.optionalDeviceSlots}.dvpl`);
|
||||||
const consumables = await readXMLDVPL<{ root: ConsumablesCommon }>(
|
const consumables = await readXMLDVPL<{ root: ConsumablesProvisionsCommon }>(
|
||||||
`${DATA}/${POI.consumablesCommon}.dvpl`,
|
`${DATA}/${POI.consumablesCommon}.dvpl`,
|
||||||
);
|
);
|
||||||
|
const provisions = await readXMLDVPL<{ root: ConsumablesProvisionsCommon }>(
|
||||||
|
`${DATA}/${POI.provisionsCommon}.dvpl`,
|
||||||
|
);
|
||||||
|
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
nations.map(async (nation) => {
|
nations.map(async (nation) => {
|
||||||
@@ -342,6 +348,7 @@ export async function buildDefinitions(production: boolean) {
|
|||||||
id: tankId,
|
id: tankId,
|
||||||
equipment,
|
equipment,
|
||||||
consumables: tankDefinition.root.consumableSlots,
|
consumables: tankDefinition.root.consumableSlots,
|
||||||
|
provisions: tankDefinition.root.provisionSlots,
|
||||||
name:
|
name:
|
||||||
(tank.shortUserString
|
(tank.shortUserString
|
||||||
? strings[tank.shortUserString] ??
|
? strings[tank.shortUserString] ??
|
||||||
@@ -646,9 +653,10 @@ export async function buildDefinitions(production: boolean) {
|
|||||||
include: [],
|
include: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
const includeRaw = consumable.vehicleFilter.include.vehicle;
|
const includeRaw = consumable.vehicleFilter?.include.vehicle;
|
||||||
const excludeRaw = consumable.vehicleFilter.exclude?.vehicle;
|
const excludeRaw = consumable.vehicleFilter?.exclude?.vehicle;
|
||||||
|
|
||||||
|
if (includeRaw) {
|
||||||
if ('minLevel' in includeRaw) {
|
if ('minLevel' in includeRaw) {
|
||||||
consumableDefinitions[consumable.id].include.push({
|
consumableDefinitions[consumable.id].include.push({
|
||||||
type: 'tier',
|
type: 'tier',
|
||||||
@@ -661,6 +669,7 @@ export async function buildDefinitions(production: boolean) {
|
|||||||
ids: includeRaw.name.split(' ').map((key) => tankStringIdMap[key]),
|
ids: includeRaw.name.split(' ').map((key) => tankStringIdMap[key]),
|
||||||
});
|
});
|
||||||
} else throw new SyntaxError('Unhandled include type');
|
} else throw new SyntaxError('Unhandled include type');
|
||||||
|
}
|
||||||
|
|
||||||
if (excludeRaw) {
|
if (excludeRaw) {
|
||||||
consumableDefinitions[consumable.id].exclude = [];
|
consumableDefinitions[consumable.id].exclude = [];
|
||||||
@@ -675,7 +684,7 @@ export async function buildDefinitions(production: boolean) {
|
|||||||
type: 'category',
|
type: 'category',
|
||||||
categories: excludeRaw.extendedTags.split(
|
categories: excludeRaw.extendedTags.split(
|
||||||
' ',
|
' ',
|
||||||
) as ConsumableDefinitionFilterCategory[],
|
) as TankFilterDefinitionCategory[],
|
||||||
});
|
});
|
||||||
} else throw new SyntaxError('Unhandled exclude type');
|
} else throw new SyntaxError('Unhandled exclude type');
|
||||||
}
|
}
|
||||||
@@ -685,7 +694,9 @@ export async function buildDefinitions(production: boolean) {
|
|||||||
...consumable.script.bonusValues,
|
...consumable.script.bonusValues,
|
||||||
}).forEach(([effectName, effect]) => {
|
}).forEach(([effectName, effect]) => {
|
||||||
if (
|
if (
|
||||||
!consumableEffectSuffixes.some((suffix) => effectName.endsWith(suffix))
|
!consumableProvisionEffectSuffixes.some((suffix) =>
|
||||||
|
effectName.endsWith(suffix),
|
||||||
|
)
|
||||||
) {
|
) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -699,6 +710,73 @@ export async function buildDefinitions(production: boolean) {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Object.values(provisions.root).forEach((provision) => {
|
||||||
|
provisionDefinitions[provision.id] = {
|
||||||
|
id: provision.id,
|
||||||
|
name:
|
||||||
|
strings[provision.userString] ??
|
||||||
|
missingStrings[provision.userString] ??
|
||||||
|
`Unknown ${provision.id}`,
|
||||||
|
include: [],
|
||||||
|
};
|
||||||
|
|
||||||
|
const includeRaw = provision.vehicleFilter?.include.vehicle;
|
||||||
|
const excludeRaw = provision.vehicleFilter?.exclude?.vehicle;
|
||||||
|
|
||||||
|
if (includeRaw) {
|
||||||
|
if ('minLevel' in includeRaw) {
|
||||||
|
provisionDefinitions[provision.id].include.push({
|
||||||
|
type: 'tier',
|
||||||
|
min: includeRaw.minLevel,
|
||||||
|
max: includeRaw.maxLevel,
|
||||||
|
});
|
||||||
|
} else if ('name' in includeRaw) {
|
||||||
|
provisionDefinitions[provision.id].include.push({
|
||||||
|
type: 'ids',
|
||||||
|
ids: includeRaw.name.split(' ').map((key) => tankStringIdMap[key]),
|
||||||
|
});
|
||||||
|
} else throw new SyntaxError('Unhandled include type');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (excludeRaw) {
|
||||||
|
provisionDefinitions[provision.id].exclude = [];
|
||||||
|
|
||||||
|
if ('name' in excludeRaw) {
|
||||||
|
provisionDefinitions[provision.id].exclude!.push({
|
||||||
|
type: 'ids',
|
||||||
|
ids: excludeRaw.name.split(' ').map((key) => tankStringIdMap[key]),
|
||||||
|
});
|
||||||
|
} else if ('extendedTags' in excludeRaw) {
|
||||||
|
provisionDefinitions[provision.id].exclude!.push({
|
||||||
|
type: 'category',
|
||||||
|
categories: excludeRaw.extendedTags.split(
|
||||||
|
' ',
|
||||||
|
) as TankFilterDefinitionCategory[],
|
||||||
|
});
|
||||||
|
} else throw new SyntaxError('Unhandled exclude type');
|
||||||
|
}
|
||||||
|
|
||||||
|
Object.entries({
|
||||||
|
...provision.script,
|
||||||
|
...provision.script.bonusValues,
|
||||||
|
}).forEach(([effectName, effect]) => {
|
||||||
|
if (
|
||||||
|
!consumableProvisionEffectSuffixes.some((suffix) =>
|
||||||
|
effectName.endsWith(suffix),
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!provisionDefinitions[provision.id].effects) {
|
||||||
|
provisionDefinitions[provision.id].effects = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
provisionDefinitions[provision.id].effects![effectName] =
|
||||||
|
effect as number;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
await commitAssets(
|
await commitAssets(
|
||||||
'definitions',
|
'definitions',
|
||||||
[
|
[
|
||||||
@@ -722,6 +800,11 @@ export async function buildDefinitions(production: boolean) {
|
|||||||
encoding: 'utf-8',
|
encoding: 'utf-8',
|
||||||
path: 'definitions/consumables.json',
|
path: 'definitions/consumables.json',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
content: JSON.stringify(provisionDefinitions),
|
||||||
|
encoding: 'utf-8',
|
||||||
|
path: 'definitions/provisions.json',
|
||||||
|
},
|
||||||
],
|
],
|
||||||
production,
|
production,
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import { config } from 'dotenv';
|
import { config } from 'dotenv';
|
||||||
import { argv } from 'process';
|
import { argv } from 'process';
|
||||||
import { camouflageIcons } from './camouflageIcons';
|
import { camouflageIcons } from './camouflageIcons';
|
||||||
import { buildCircleFlags } from './circleFlags';
|
import { circleFlags } from './circleFlags';
|
||||||
import { buildConsumableIcons } from './consumableIcons';
|
import { consumableIcons } from './consumableIcons';
|
||||||
import { buildDefinitions } from './definitions';
|
import { definitions } from './definitions';
|
||||||
import { equipmentIcons } from './equipmentIcons';
|
import { equipmentIcons } from './equipmentIcons';
|
||||||
import { buildModuleIcons } from './moduleIcons';
|
import { buildModuleIcons } from './moduleIcons';
|
||||||
import { buildScratchedFlags } from './scratchedFlags';
|
import { buildScratchedFlags } from './scratchedFlags';
|
||||||
@@ -26,14 +26,14 @@ if (!targets && !allTargets) throw new Error('No target(s) specified');
|
|||||||
const methods = [
|
const methods = [
|
||||||
buildTankModels,
|
buildTankModels,
|
||||||
buildTankArmors,
|
buildTankArmors,
|
||||||
buildDefinitions,
|
definitions,
|
||||||
buildTankIcons,
|
buildTankIcons,
|
||||||
buildScratchedFlags,
|
buildScratchedFlags,
|
||||||
buildCircleFlags,
|
circleFlags,
|
||||||
buildShellIcons,
|
buildShellIcons,
|
||||||
buildModuleIcons,
|
buildModuleIcons,
|
||||||
equipmentIcons,
|
equipmentIcons,
|
||||||
buildConsumableIcons,
|
consumableIcons,
|
||||||
camouflageIcons,
|
camouflageIcons,
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import { Flex, Heading, Text } from '@radix-ui/themes';
|
import { Flex, Heading, Text } from '@radix-ui/themes';
|
||||||
import { use } from 'react';
|
import { use } from 'react';
|
||||||
import { ModuleButton } from '../../../../../../../components/ModuleButton';
|
import { ModuleButton } from '../../../../../../../components/ModuleButton';
|
||||||
import { checkConsumableInclusivity } from '../../../../../../../core/blitzkrieg/checkConsumableInclusivity';
|
import { checkConsumableProvisionInclusivity } from '../../../../../../../core/blitzkrieg/checkConsumableInclusivity';
|
||||||
import { consumableDefinitions } from '../../../../../../../core/blitzkrieg/consumablesDefinitions';
|
import { consumableDefinitions } from '../../../../../../../core/blitzkrieg/consumableDefinitions';
|
||||||
import { useDuel } from '../../../../../../../stores/duel';
|
import { useDuel } from '../../../../../../../stores/duel';
|
||||||
import {
|
import {
|
||||||
mutateTankopediaTemporary,
|
mutateTankopediaTemporary,
|
||||||
@@ -15,7 +15,11 @@ export function Consumables() {
|
|||||||
const consumables = useTankopediaTemporary((state) => state.consumables);
|
const consumables = useTankopediaTemporary((state) => state.consumables);
|
||||||
const consumablesList = Object.values(awaitedConsumableDefinitions).filter(
|
const consumablesList = Object.values(awaitedConsumableDefinitions).filter(
|
||||||
(consumable) =>
|
(consumable) =>
|
||||||
checkConsumableInclusivity(consumable, protagonist.tank, protagonist.gun),
|
checkConsumableProvisionInclusivity(
|
||||||
|
consumable,
|
||||||
|
protagonist.tank,
|
||||||
|
protagonist.gun,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -0,0 +1,63 @@
|
|||||||
|
import { Flex, Heading, Text } from '@radix-ui/themes';
|
||||||
|
import { use } from 'react';
|
||||||
|
import { ModuleButton } from '../../../../../../../components/ModuleButton';
|
||||||
|
import { checkConsumableProvisionInclusivity } from '../../../../../../../core/blitzkrieg/checkConsumableInclusivity';
|
||||||
|
import { provisionDefinitions } from '../../../../../../../core/blitzkrieg/provisionDefinitions';
|
||||||
|
import { useDuel } from '../../../../../../../stores/duel';
|
||||||
|
import {
|
||||||
|
mutateTankopediaTemporary,
|
||||||
|
useTankopediaTemporary,
|
||||||
|
} from '../../../../../../../stores/tankopedia';
|
||||||
|
|
||||||
|
export function Provisions() {
|
||||||
|
const protagonist = useDuel((state) => state.protagonist!);
|
||||||
|
const awaitedProvisionDefinitions = use(provisionDefinitions);
|
||||||
|
const provisions = useTankopediaTemporary((state) => state.provisions);
|
||||||
|
const provisionsList = Object.values(awaitedProvisionDefinitions).filter(
|
||||||
|
(provision) =>
|
||||||
|
checkConsumableProvisionInclusivity(
|
||||||
|
provision,
|
||||||
|
protagonist.tank,
|
||||||
|
protagonist.gun,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Flex gap="2" direction="column">
|
||||||
|
<Heading size="4">
|
||||||
|
Provisions <Text color="gray">(max {protagonist.tank.provisions})</Text>
|
||||||
|
</Heading>
|
||||||
|
|
||||||
|
<Flex>
|
||||||
|
{provisionsList.map((provision, index) => {
|
||||||
|
const selected = provisions.includes(provision.id);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ModuleButton
|
||||||
|
first={index === 0}
|
||||||
|
last={index === provisionsList.length - 1}
|
||||||
|
rowChild
|
||||||
|
type="provision"
|
||||||
|
disabled={
|
||||||
|
protagonist.tank.provisions === provisions.length && !selected
|
||||||
|
}
|
||||||
|
provision={provision.id}
|
||||||
|
selected={selected}
|
||||||
|
onClick={() => {
|
||||||
|
mutateTankopediaTemporary((draft) => {
|
||||||
|
if (selected) {
|
||||||
|
draft.provisions = draft.provisions.filter(
|
||||||
|
(id) => id !== provision.id,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
draft.provisions.push(provision.id);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</Flex>
|
||||||
|
</Flex>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -3,6 +3,7 @@ import { Camouflage } from './components/Camouflage';
|
|||||||
import { Consumables } from './components/Consumables';
|
import { Consumables } from './components/Consumables';
|
||||||
import { Equipments } from './components/Equipments';
|
import { Equipments } from './components/Equipments';
|
||||||
import { Modules } from './components/Modules';
|
import { Modules } from './components/Modules';
|
||||||
|
import { Provisions } from './components/Provisions';
|
||||||
|
|
||||||
export function Configure() {
|
export function Configure() {
|
||||||
return (
|
return (
|
||||||
@@ -14,13 +15,10 @@ export function Configure() {
|
|||||||
<Equipments />
|
<Equipments />
|
||||||
<Consumables />
|
<Consumables />
|
||||||
<Camouflage />
|
<Camouflage />
|
||||||
|
<Provisions />
|
||||||
</Flex>
|
</Flex>
|
||||||
|
|
||||||
{/*
|
{/*
|
||||||
<Flex gap="4" direction="column">
|
|
||||||
<Heading size="5">Camouflage</Heading>
|
|
||||||
</Flex>
|
|
||||||
|
|
||||||
<Flex gap="4" direction="column">
|
<Flex gap="4" direction="column">
|
||||||
<Heading size="5">Provisions</Heading>
|
<Heading size="5">Provisions</Heading>
|
||||||
</Flex> */}
|
</Flex> */}
|
||||||
|
|||||||
@@ -25,6 +25,10 @@ type ModuleButtonProps = Omit<ComponentProps<typeof Button>, 'type'> & {
|
|||||||
type: 'consumable';
|
type: 'consumable';
|
||||||
consumable: number;
|
consumable: number;
|
||||||
}
|
}
|
||||||
|
| {
|
||||||
|
type: 'provision';
|
||||||
|
provision: number;
|
||||||
|
}
|
||||||
| {
|
| {
|
||||||
type: 'camouflage';
|
type: 'camouflage';
|
||||||
}
|
}
|
||||||
@@ -89,6 +93,8 @@ export function ModuleButton({
|
|||||||
? `icons/consumables/${props.consumable}.webp`
|
? `icons/consumables/${props.consumable}.webp`
|
||||||
: props.type === 'camouflage'
|
: props.type === 'camouflage'
|
||||||
? `icons/camo.webp`
|
? `icons/camo.webp`
|
||||||
|
: props.type === 'provision'
|
||||||
|
? `icons/provisions/${props.provision}.webp`
|
||||||
: `icons/equipment/${props.equipment}.webp`,
|
: `icons/equipment/${props.equipment}.webp`,
|
||||||
)}
|
)}
|
||||||
style={imageStyles}
|
style={imageStyles}
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
import { ConsumableEntry } from './consumablesDefinitions';
|
import { ConsumableEntry } from './consumableDefinitions';
|
||||||
|
import { ProvisionEntry } from './provisionDefinitions';
|
||||||
import { GunDefinition, TankDefinition } from './tankDefinitions';
|
import { GunDefinition, TankDefinition } from './tankDefinitions';
|
||||||
|
|
||||||
export function checkConsumableInclusivity(
|
export function checkConsumableProvisionInclusivity(
|
||||||
consumable: ConsumableEntry,
|
consumableProvision: ConsumableEntry | ProvisionEntry,
|
||||||
tank: TankDefinition,
|
tank: TankDefinition,
|
||||||
gun: GunDefinition,
|
gun: GunDefinition,
|
||||||
) {
|
) {
|
||||||
const included = consumable.include.every((rule) => {
|
const included = consumableProvision.include.every((rule) => {
|
||||||
switch (rule.type) {
|
switch (rule.type) {
|
||||||
case 'tier':
|
case 'tier':
|
||||||
return rule.min <= tank.tier && tank.tier <= rule.max;
|
return rule.min <= tank.tier && tank.tier <= rule.max;
|
||||||
@@ -18,7 +19,7 @@ export function checkConsumableInclusivity(
|
|||||||
throw new SyntaxError('Category filtering found in include rule');
|
throw new SyntaxError('Category filtering found in include rule');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
const excluded = consumable.exclude?.some((rule) => {
|
const excluded = consumableProvision.exclude?.some((rule) => {
|
||||||
switch (rule.type) {
|
switch (rule.type) {
|
||||||
case 'tier':
|
case 'tier':
|
||||||
return rule.min <= tank.tier && tank.tier <= rule.max;
|
return rule.min <= tank.tier && tank.tier <= rule.max;
|
||||||
|
|||||||
+5
-5
@@ -1,8 +1,8 @@
|
|||||||
import { asset } from './asset';
|
import { asset } from './asset';
|
||||||
|
|
||||||
export type ConsumableDefinitionFilterCategory = 'clip';
|
export type TankFilterDefinitionCategory = 'clip';
|
||||||
|
|
||||||
type ConsumableDefinitionFilter =
|
export type TankFilterDefinition =
|
||||||
| {
|
| {
|
||||||
type: 'tier';
|
type: 'tier';
|
||||||
min: number;
|
min: number;
|
||||||
@@ -14,15 +14,15 @@ type ConsumableDefinitionFilter =
|
|||||||
}
|
}
|
||||||
| {
|
| {
|
||||||
type: 'category';
|
type: 'category';
|
||||||
categories: ConsumableDefinitionFilterCategory[];
|
categories: TankFilterDefinitionCategory[];
|
||||||
};
|
};
|
||||||
|
|
||||||
export interface ConsumableEntry {
|
export interface ConsumableEntry {
|
||||||
id: number;
|
id: number;
|
||||||
name: string;
|
name: string;
|
||||||
effects?: Record<string, number>;
|
effects?: Record<string, number>;
|
||||||
include: ConsumableDefinitionFilter[];
|
include: TankFilterDefinition[];
|
||||||
exclude?: ConsumableDefinitionFilter[];
|
exclude?: TankFilterDefinition[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ConsumableDefinitions {
|
export interface ConsumableDefinitions {
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
import { asset } from './asset';
|
||||||
|
import { TankFilterDefinition } from './consumableDefinitions';
|
||||||
|
|
||||||
|
export interface ProvisionEntry {
|
||||||
|
id: number;
|
||||||
|
name: string;
|
||||||
|
effects?: Record<string, number>;
|
||||||
|
include: TankFilterDefinition[];
|
||||||
|
exclude?: TankFilterDefinition[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ProvisionDefinitions {
|
||||||
|
[key: string]: ProvisionEntry;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const provisionDefinitions = fetch(
|
||||||
|
asset('definitions/provisions.json'),
|
||||||
|
{
|
||||||
|
cache: 'no-cache',
|
||||||
|
},
|
||||||
|
).then(async (response) => response.json() as Promise<ProvisionDefinitions>);
|
||||||
@@ -20,6 +20,7 @@ export interface TankDefinition {
|
|||||||
name_full?: string;
|
name_full?: string;
|
||||||
tree_type: TreeTypeString;
|
tree_type: TreeTypeString;
|
||||||
consumables: number;
|
consumables: number;
|
||||||
|
provisions: number;
|
||||||
tier: Tier;
|
tier: Tier;
|
||||||
type: TankType;
|
type: TankType;
|
||||||
testing?: boolean;
|
testing?: boolean;
|
||||||
|
|||||||
@@ -58,6 +58,7 @@ interface TankopediaTemporary {
|
|||||||
equipmentMatrix: EquipmentMatrix;
|
equipmentMatrix: EquipmentMatrix;
|
||||||
mode: TankopediaMode;
|
mode: TankopediaMode;
|
||||||
consumables: number[];
|
consumables: number[];
|
||||||
|
provisions: number[];
|
||||||
camouflage: boolean;
|
camouflage: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -107,6 +108,7 @@ export const useTankopediaTemporary = create<TankopediaTemporary>()(
|
|||||||
],
|
],
|
||||||
mode: 'model',
|
mode: 'model',
|
||||||
consumables: [],
|
consumables: [],
|
||||||
|
provisions: [],
|
||||||
camouflage: false,
|
camouflage: false,
|
||||||
})),
|
})),
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in new issue
Block a user