feat: start of assault shells

This commit is contained in:
TrèsAbhi committed 2025-07-31 13:40:30 -05:00
1 parent 20f7119854
commit 83b7de77de
2 files changed
+70 -36

No files matched your search

@@ -157,6 +157,16 @@ message GunDefinitionBase {
required float dispersion_damaged = 13; required float dispersion_damaged = 13;
repeated Unlock unlocks = 14; repeated Unlock unlocks = 14;
required uint32 shell_capacity = 15; required uint32 shell_capacity = 15;
optional AssaultRanges assault_ranges = 16;
}
message AssaultRanges {
repeated AssaultRange ranges = 1;
}
message AssaultRange {
required float distance = 1;
required float factor = 2;
} }
message ShellDefinition { message ShellDefinition {
+60 -36
View File
@@ -274,6 +274,15 @@ interface VehicleDefinitions {
pumpGunReloadTimes?: string; pumpGunReloadTimes?: string;
clip?: { count: number; rate: number }; clip?: { count: number; rate: number };
models: { undamaged: string }; models: { undamaged: string };
extras?: {
trayShell?: {
kinds: string;
sectors: Record<
string,
{ id: number; distance: number; factor: number }[]
>;
};
};
}; };
}; };
}; };
@@ -561,11 +570,6 @@ export async function definitions() {
(nations) => nations.filter((nation) => nation !== 'common'), (nations) => nations.filter((nation) => nation !== 'common'),
); );
const tankStringIdMap: Record<string, number> = {}; const tankStringIdMap: Record<string, number> = {};
const stringsCache = await fetch(
'https://stufficons.wgcdn.co/localizations/en.yaml',
)
.then((response) => response.text())
.then((string) => parseYaml(string) as BlitzStrings);
const optionalDevices = await readXMLDVPL<{ root: OptionalDevices }>( const optionalDevices = await readXMLDVPL<{ root: OptionalDevices }>(
`${DATA}/XML/item_defs/vehicles/common/optional_devices.xml`, `${DATA}/XML/item_defs/vehicles/common/optional_devices.xml`,
); );
@@ -573,6 +577,11 @@ export async function definitions() {
await Promise.all( await Promise.all(
SUPPORTED_LOCALES.map(async (locale) => { SUPPORTED_LOCALES.map(async (locale) => {
if (locale !== 'en') {
stringsI18n[locale] = {};
return;
}
const blitzLocale = SUPPORTED_LOCALE_BLITZ_MAP[locale]; const blitzLocale = SUPPORTED_LOCALE_BLITZ_MAP[locale];
const cache = await fetch( const cache = await fetch(
`https://stufficons.wgcdn.co/localizations/${blitzLocale}.yaml`, `https://stufficons.wgcdn.co/localizations/${blitzLocale}.yaml`,
@@ -723,8 +732,7 @@ export async function definitions() {
const slugRequesters = new Map<string, { id: number; key: string }[]>(); const slugRequesters = new Map<string, { id: number; key: string }[]>();
const idToNation: Record<number, string> = {}; const idToNation: Record<number, string> = {};
await Promise.all( for (const nation of nations) {
nations.map(async (nation) => {
const tankList = await readXMLDVPL<{ root: VehicleDefinitionList }>( const tankList = await readXMLDVPL<{ root: VehicleDefinitionList }>(
`${DATA}/XML/item_defs/vehicles/${nation}/list.xml`, `${DATA}/XML/item_defs/vehicles/${nation}/list.xml`,
); );
@@ -734,10 +742,10 @@ export async function definitions() {
const tank = tankList.root[tankKey]; const tank = tankList.root[tankKey];
const tankId = toUniqueId(nation, tank.id); const tankId = toUniqueId(nation, tank.id);
const name = ( const name = (
(tank.shortUserString (tank.shortUserString ? getString(tank.shortUserString) : undefined) ??
? getString(tank.shortUserString) getString(tank.userString)
: undefined) ?? getString(tank.userString)
).locales.en; ).locales.en;
let slug = deburr(name).toLowerCase(); let slug = deburr(name).toLowerCase();
@@ -754,8 +762,7 @@ export async function definitions() {
slugRequesters.set(slug, [{ id: tankId, key: tankKey }]); slugRequesters.set(slug, [{ id: tankId, key: tankKey }]);
} }
} }
}), }
);
const slugs = new Map<number, string>(); const slugs = new Map<number, string>();
@@ -807,8 +814,7 @@ export async function definitions() {
} }
}); });
await Promise.all( for (const nation of nations) {
nations.map(async (nation) => {
const tankList = await readXMLDVPL<{ root: VehicleDefinitionList }>( const tankList = await readXMLDVPL<{ root: VehicleDefinitionList }>(
`${DATA}/XML/item_defs/vehicles/${nation}/list.xml`, `${DATA}/XML/item_defs/vehicles/${nation}/list.xml`,
); );
@@ -887,6 +893,7 @@ export async function definitions() {
.split(' ') .split(' ')
.map(Number) as Vector3Tuple; .map(Number) as Vector3Tuple;
const tankId = toUniqueId(nation, tank.id); const tankId = toUniqueId(nation, tank.id);
const tankTags = tank.tags.split(' '); const tankTags = tank.tags.split(' ');
const hullArmor: Armor = { spaced: [], thickness: {} }; const hullArmor: Armor = { spaced: [], thickness: {} };
const equipment = tankDefinition.root.optDevicePreset; const equipment = tankDefinition.root.optDevicePreset;
@@ -977,8 +984,7 @@ export async function definitions() {
const camouflages = camouflagesXmlEntries const camouflages = camouflagesXmlEntries
.filter(([, camo]) => { .filter(([, camo]) => {
if (!camo.vehicleFilter.include) return false; if (!camo.vehicleFilter.include) return false;
if (camo.unlockCostCategory !== 'legendary-skins-gold') if (camo.unlockCostCategory !== 'legendary-skins-gold') return false;
return false;
const includeArray = Array.isArray(camo.vehicleFilter.include) const includeArray = Array.isArray(camo.vehicleFilter.include)
? camo.vehicleFilter.include ? camo.vehicleFilter.include
@@ -1053,8 +1059,7 @@ export async function definitions() {
modelDefinitions.models[tankId] = { modelDefinitions.models[tankId] = {
armor: hullArmor, armor: hullArmor,
turret_origin: vector3TupleToBlitzkit(turretOrigin), turret_origin: vector3TupleToBlitzkit(turretOrigin),
initial_turret_rotation: tankDefinition.root.hull initial_turret_rotation: tankDefinition.root.hull.turretInitialRotation
.turretInitialRotation
? { ? {
yaw: tankDefinition.root.hull.turretInitialRotation.yaw, yaw: tankDefinition.root.hull.turretInitialRotation.yaw,
pitch: tankDefinition.root.hull.turretInitialRotation.pitch, pitch: tankDefinition.root.hull.turretInitialRotation.pitch,
@@ -1192,16 +1197,12 @@ export async function definitions() {
bounding_box: { bounding_box: {
min: vector3TupleToBlitzkit( min: vector3TupleToBlitzkit(
tankParameters.collision[ tankParameters.collision[
parsePath( parsePath(turret.hitTester.collisionModel).name.toLowerCase()
turret.hitTester.collisionModel,
).name.toLowerCase()
].bbox.min, ].bbox.min,
), ),
max: vector3TupleToBlitzkit( max: vector3TupleToBlitzkit(
tankParameters.collision[ tankParameters.collision[
parsePath( parsePath(turret.hitTester.collisionModel).name.toLowerCase()
turret.hitTester.collisionModel,
).name.toLowerCase()
].bbox.max, ].bbox.max,
), ),
}, },
@@ -1211,8 +1212,7 @@ export async function definitions() {
const gun = turret.guns[gunKey]; const gun = turret.guns[gunKey];
const gunId = toUniqueId(nation, gunList.root.ids[gunKey]); const gunId = toUniqueId(nation, gunList.root.ids[gunKey]);
const gunListEntry = gunList.root.shared[gunKey]; const gunListEntry = gunList.root.shared[gunKey];
const pitchLimitsRaw = const pitchLimitsRaw = gun.pitchLimits ?? gunListEntry.pitchLimits;
gun.pitchLimits ?? gunListEntry.pitchLimits;
const gunPitch = ( const gunPitch = (
typeof pitchLimitsRaw === 'string' typeof pitchLimitsRaw === 'string'
? pitchLimitsRaw ? pitchLimitsRaw
@@ -1252,6 +1252,34 @@ export async function definitions() {
tankParameters.maskSlice?.[maskName]?.enabled ?? false; tankParameters.maskSlice?.[maskName]?.enabled ?? false;
let mask: number | undefined; let mask: number | undefined;
if (gun.extras?.trayShell) {
const kinds = gun.extras.trayShell.kinds
.split(' ')
.map((string) => {
const trimmed = string.trim();
if (trimmed in blitzShellKindToBlitzkit) {
return blitzShellKindToBlitzkit[trimmed as ShellKind];
}
throw new SyntaxError(`Invalid shell kind: ${trimmed}`);
});
const sectorNames = Object.keys(gun.extras.trayShell.sectors);
if (sectorNames.length !== 1 || sectorNames[0] !== 'sector') {
throw new SyntaxError('Invalid tray shell sector');
}
const sector = gun.extras.trayShell.sectors.sector;
gun.assault_ranges = {
ranges: sector.map((value) => ({
factor: value.factor,
distance: value.distance,
})),
};
}
if (maskEnabled) { if (maskEnabled) {
const maskRaw = tankParameters.maskSlice![maskName]!; const maskRaw = tankParameters.maskSlice![maskName]!;
mask = maskRaw.planePosition[1]; mask = maskRaw.planePosition[1];
@@ -1464,8 +1492,7 @@ export async function definitions() {
}); });
}); });
Object.values(tankDefinitions.tanks[tankId].turrets).forEach( Object.values(tankDefinitions.tanks[tankId].turrets).forEach((turret) => {
(turret) => {
turret.research_cost = turretXps.get(turret.id); turret.research_cost = turretXps.get(turret.id);
Object.values(turret.guns).forEach((gunRaw) => { Object.values(turret.guns).forEach((gunRaw) => {
@@ -1473,21 +1500,17 @@ export async function definitions() {
gunRaw.gun_type!.value.base.id, gunRaw.gun_type!.value.base.id,
); );
}); });
}, });
);
Object.values(tankDefinitions.tanks[tankId].engines).forEach( Object.values(tankDefinitions.tanks[tankId].engines).forEach((engine) => {
(engine) => {
engine.research_cost = engineXps.get(engine.id); engine.research_cost = engineXps.get(engine.id);
}, });
);
Object.values(tankDefinitions.tanks[tankId].tracks).forEach((track) => { Object.values(tankDefinitions.tanks[tankId].tracks).forEach((track) => {
track.research_cost = trackXps.get(track.id); track.research_cost = trackXps.get(track.id);
}); });
} }
}), }
);
Object.values(tankDefinitions.tanks).forEach((tank) => { Object.values(tankDefinitions.tanks).forEach((tank) => {
tank.research_cost = tankXps.get(tank.id); tank.research_cost = tankXps.get(tank.id);
@@ -1769,6 +1792,7 @@ export async function definitions() {
}; };
}); });
return;
await commitAssets('definitions', [ await commitAssets('definitions', [
{ {
content: GameDefinitions.encode(gameDefinitions).finish(), content: GameDefinitions.encode(gameDefinitions).finish(),