From d9c2f53c6a122b460079295b875f9774a6a00d0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Fri, 16 Aug 2024 13:48:23 -0500 Subject: [PATCH] feat: ability defs --- scripts/buildAssets/definitions.ts | 257 +++++++++++++-------- src/core/blitzkit/consumableDefinitions.ts | 15 +- src/core/blitzkit/gameDefinitions.ts | 7 + src/core/blitzkit/provisionDefinitions.ts | 15 +- 4 files changed, 190 insertions(+), 104 deletions(-) diff --git a/scripts/buildAssets/definitions.ts b/scripts/buildAssets/definitions.ts index a040c3839..5aa659b0e 100644 --- a/scripts/buildAssets/definitions.ts +++ b/scripts/buildAssets/definitions.ts @@ -12,6 +12,7 @@ import { CamouflageDefinitions } from '../../src/core/blitzkit/camouflageDefinit import { commitAssets } from '../../src/core/blitzkit/commitAssets'; import { ConsumableDefinitions, + ConsumableEntry, TankFilterDefinitionCategory, } from '../../src/core/blitzkit/consumableDefinitions'; import { @@ -25,7 +26,10 @@ import { ModelArmor, ModelDefinitions, } from '../../src/core/blitzkit/modelDefinitions'; -import { ProvisionDefinitions } from '../../src/core/blitzkit/provisionDefinitions'; +import { + ProvisionDefinitions, + ProvisionEntry, +} from '../../src/core/blitzkit/provisionDefinitions'; import { SkillDefinitions } from '../../src/core/blitzkit/skillDefinitions'; import { superCompress } from '../../src/core/blitzkit/superCompress'; import { @@ -450,6 +454,7 @@ export async function definitions(production: boolean) { ) ).available_nations, gameModes: {}, + roles: {}, }; const tankDefinitions: TankDefinitions = {}; const camouflageDefinitions: CamouflageDefinitions = {}; @@ -486,12 +491,43 @@ export async function definitions(production: boolean) { const optionalDeviceSlots = await readXMLDVPL<{ root: OptionalDeviceSlots; }>(`${DATA}/XML/item_defs/vehicles/common/optional_device_slots.xml.dvpl`); - const consumables = await readXMLDVPL<{ root: ConsumablesCommon }>( - `${DATA}/XML/item_defs/vehicles/common/consumables/common.xml.dvpl`, - ); - const provisions = await readXMLDVPL<{ root: ProvisionsCommon }>( - `${DATA}/XML/item_defs/vehicles/common/provisions/common.xml.dvpl`, - ); + const consumables: ConsumablesCommon = {}; + const provisions: ProvisionsCommon = {}; + + for (const match of ( + await readStringDVPL( + `${DATA}/XML/item_defs/vehicles/common/consumables/list.xml.dvpl`, + ) + ).matchAll(//g)) { + if (match[1] === 'prototypes') continue; + + Object.assign( + consumables, + ( + await readXMLDVPL<{ root: ConsumablesCommon }>( + `${DATA}/XML/item_defs/vehicles/common/consumables/${match[1]}.xml.dvpl`, + ) + ).root, + ); + } + + for (const match of ( + await readStringDVPL( + `${DATA}/XML/item_defs/vehicles/common/provisions/list.xml.dvpl`, + ) + ).matchAll(//g)) { + if (match[1] === 'prototypes') continue; + + Object.assign( + provisions, + ( + await readXMLDVPL<{ root: ConsumablesCommon }>( + `${DATA}/XML/item_defs/vehicles/common/provisions/${match[1]}.xml.dvpl`, + ) + ).root, + ); + } + const avatar = await readXMLDVPL<{ root: Avatar }>( `${DATA}/XML/item_defs/tankmen/avatar.xml.dvpl`, ); @@ -514,6 +550,8 @@ export async function definitions(production: boolean) { const combatRoles = await readYAMLDVPL( `${DATA}/XML/item_defs/vehicles/common/combat_roles.yaml.dvpl`, ); + const consumableNativeNames: Record = {}; + const provisionNativeNames: Record = {}; for (const match of squadBattleTypeStyles.Prototypes[0].components.UIDataLocalBindingsComponent.data[1][2].matchAll( /"(\d+)" -> "(battleType\/([a-zA-Z]+))"/g, @@ -785,8 +823,6 @@ export async function definitions(production: boolean) { ); } - console.log(combatRoles[role].id); - tankDefinitions[tankId].roles[id] = combatRoles[role].id; }); } @@ -1240,126 +1276,140 @@ export async function definitions(production: boolean) { }, ); - Object.values(consumables.root).forEach((consumable) => { - consumableDefinitions[consumable.id] = { + Object.entries(consumables).forEach(([key, consumable]) => { + consumableNativeNames[key] = consumable.id; + + const entry = { id: consumable.id, + gameMode: 'gameModeFilter' in consumable, cooldown: consumable.script.cooldown, duration: consumable.script.duration, name: strings[consumable.userString] ?? missingStrings[consumable.userString] ?? `Unknown ${consumable.id}`, - include: [], - }; + } as ConsumableEntry; + consumableDefinitions[consumable.id] = entry; const includeRaw = consumable.vehicleFilter?.include.vehicle; const excludeRaw = consumable.vehicleFilter?.exclude?.vehicle; - if (includeRaw) { - if ('minLevel' in includeRaw) { - consumableDefinitions[consumable.id].include.push({ - type: 'tier', - min: includeRaw.minLevel, - max: includeRaw.maxLevel, - }); - } else if ('name' in includeRaw) { - consumableDefinitions[consumable.id].include.push({ - type: 'ids', - ids: includeRaw.name.split(' ').map((key) => tankStringIdMap[key]), - }); - } else throw new SyntaxError('Unhandled include type'); + if (!entry.gameMode) { + if (includeRaw) { + entry.include = []; - if (consumable.vehicleFilter?.include.nations) { - consumableDefinitions[consumable.id].include.push({ - type: 'nation', - nations: consumable.vehicleFilter.include.nations.split(' '), - }); + if ('minLevel' in includeRaw) { + entry.include.push({ + type: 'tier', + min: includeRaw.minLevel, + max: includeRaw.maxLevel, + }); + } else if ('name' in includeRaw) { + entry.include.push({ + type: 'ids', + ids: includeRaw.name.split(' ').map((key) => tankStringIdMap[key]), + }); + } else throw new SyntaxError('Unhandled include type'); + + if (consumable.vehicleFilter?.include.nations) { + entry.include.push({ + type: 'nation', + nations: consumable.vehicleFilter.include.nations.split(' '), + }); + } } - } - if (excludeRaw) { - consumableDefinitions[consumable.id].exclude = []; + if (excludeRaw) { + entry.exclude = []; - if ('name' in excludeRaw) { - consumableDefinitions[consumable.id].exclude!.push({ - type: 'ids', - ids: excludeRaw.name.split(' ').map((key) => tankStringIdMap[key]), - }); - } else if ('extendedTags' in excludeRaw) { - consumableDefinitions[consumable.id].exclude!.push({ - type: 'category', - categories: excludeRaw.extendedTags.split( - ' ', - ) as TankFilterDefinitionCategory[], - }); - } else throw new SyntaxError('Unhandled exclude type'); + if ('name' in excludeRaw) { + entry.exclude!.push({ + type: 'ids', + ids: excludeRaw.name.split(' ').map((key) => tankStringIdMap[key]), + }); + } else if ('extendedTags' in excludeRaw) { + entry.exclude!.push({ + type: 'category', + categories: excludeRaw.extendedTags.split( + ' ', + ) as TankFilterDefinitionCategory[], + }); + } else throw new SyntaxError('Unhandled exclude type'); - if (consumable.vehicleFilter?.exclude?.nations) { - consumableDefinitions[consumable.id].exclude!.push({ - type: 'nation', - nations: consumable.vehicleFilter.exclude.nations.split(' '), - }); + if (consumable.vehicleFilter?.exclude?.nations) { + entry.exclude!.push({ + type: 'nation', + nations: consumable.vehicleFilter.exclude.nations.split(' '), + }); + } } } }); - Object.values(provisions.root).forEach((provision) => { - provisionDefinitions[provision.id] = { + Object.entries(provisions).forEach(([key, provision]) => { + provisionNativeNames[key] = provision.id; + + const entry = { id: provision.id, + gameMode: 'gameModeFilter' in provision, name: strings[provision.userString] ?? missingStrings[provision.userString] ?? `Unknown ${provision.id}`, - include: [], - }; + } as ProvisionEntry; + provisionDefinitions[provision.id] = entry; 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 (!entry.gameMode) { + if (includeRaw) { + entry.include = []; - if (provision.vehicleFilter?.include.nations) { - provisionDefinitions[provision.id].include.push({ - type: 'nation', - nations: provision.vehicleFilter.include.nations.split(' '), - }); + if ('minLevel' in includeRaw) { + entry.include.push({ + type: 'tier', + min: includeRaw.minLevel, + max: includeRaw.maxLevel, + }); + } else if ('name' in includeRaw) { + entry.include.push({ + type: 'ids', + ids: includeRaw.name.split(' ').map((key) => tankStringIdMap[key]), + }); + } else throw new SyntaxError('Unhandled include type'); + + if (provision.vehicleFilter?.include.nations) { + entry.include.push({ + type: 'nation', + nations: provision.vehicleFilter.include.nations.split(' '), + }); + } } - } - if (excludeRaw) { - provisionDefinitions[provision.id].exclude = []; + if (excludeRaw) { + entry.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'); + if ('name' in excludeRaw) { + entry.exclude!.push({ + type: 'ids', + ids: excludeRaw.name.split(' ').map((key) => tankStringIdMap[key]), + }); + } else if ('extendedTags' in excludeRaw) { + entry.exclude!.push({ + type: 'category', + categories: excludeRaw.extendedTags.split( + ' ', + ) as TankFilterDefinitionCategory[], + }); + } else throw new SyntaxError('Unhandled exclude type'); - if (provision.vehicleFilter?.exclude?.nations) { - provisionDefinitions[provision.id].exclude!.push({ - type: 'nation', - nations: provision.vehicleFilter.exclude.nations.split(' '), - }); + if (provision.vehicleFilter?.exclude?.nations) { + entry.exclude!.push({ + type: 'nation', + nations: provision.vehicleFilter.exclude.nations.split(' '), + }); + } } } @@ -1369,6 +1419,22 @@ export async function definitions(production: boolean) { } }); + Object.entries(combatRoles).forEach(([, value]) => { + gameDefinitions.roles[value.id] = { provisions: [], consumables: [] }; + + value.default_abilities.forEach((ability) => { + if (ability in consumableNativeNames) { + gameDefinitions.roles[value.id].consumables.push( + consumableNativeNames[ability], + ); + } else if (ability in provisionNativeNames) { + gameDefinitions.roles[value.id].provisions.push( + provisionNativeNames[ability], + ); + } else throw new Error(`Unknown ability ${ability}`); + }); + }); + Object.entries(avatar.root.skillsByClasses).forEach(([tankClass, skills]) => { skillDefinitions.classes[tankClass as TankClass] = skills.split(' '); }); @@ -1380,7 +1446,6 @@ export async function definitions(production: boolean) { }; }); - return; await commitAssets( 'definitions', [ diff --git a/src/core/blitzkit/consumableDefinitions.ts b/src/core/blitzkit/consumableDefinitions.ts index 76a417488..d56d2a570 100644 --- a/src/core/blitzkit/consumableDefinitions.ts +++ b/src/core/blitzkit/consumableDefinitions.ts @@ -22,14 +22,21 @@ export type TankFilterDefinition = nations: string[]; }; -export interface ConsumableEntry { +export type ConsumableEntry = { id: number; name: string; cooldown: number; duration?: number; - include: TankFilterDefinition[]; - exclude?: TankFilterDefinition[]; -} +} & ( + | { + gameMode: false; + include: TankFilterDefinition[]; + exclude?: TankFilterDefinition[]; + } + | { + gameMode: true; + } +); export interface ConsumableDefinitions { [key: string]: ConsumableEntry; diff --git a/src/core/blitzkit/gameDefinitions.ts b/src/core/blitzkit/gameDefinitions.ts index d167e5d46..4270a07dd 100644 --- a/src/core/blitzkit/gameDefinitions.ts +++ b/src/core/blitzkit/gameDefinitions.ts @@ -9,6 +9,13 @@ export interface GameDefinitions { version: string; nations: string[]; gameModes: Record; + roles: Record< + number, + { + provisions: number[]; + consumables: number[]; + } + >; } export const gameDefinitions = fetchCdonLz4( diff --git a/src/core/blitzkit/provisionDefinitions.ts b/src/core/blitzkit/provisionDefinitions.ts index 9f70f90af..6d8451427 100644 --- a/src/core/blitzkit/provisionDefinitions.ts +++ b/src/core/blitzkit/provisionDefinitions.ts @@ -2,13 +2,20 @@ import { asset } from './asset'; import { TankFilterDefinition } from './consumableDefinitions'; import { fetchCdonLz4 } from './fetchCdonLz4'; -export interface ProvisionEntry { +export type ProvisionEntry = { id: number; name: string; - include: TankFilterDefinition[]; - exclude?: TankFilterDefinition[]; crew?: number; -} +} & ( + | { + gameMode: false; + include: TankFilterDefinition[]; + exclude?: TankFilterDefinition[]; + } + | { + gameMode: true; + } +); export interface ProvisionDefinitions { [key: string]: ProvisionEntry;