feat: rename a bit

This commit is contained in:
TrèsAbhi committed 2025-12-18 15:30:18 -06:00
1 parent 66eaaef6de
commit 6ce1135835
8 files changed
+104 -59

No files matched your search

@@ -0,0 +1,213 @@
import { StandardSinglePrice } from "@protos/blitz_static_standard_single_price";
import { PenetrationGroup } from "@protos/blitz_static_tank_penetration_group";
import {
PenetrationGroupUpgrade,
PitchLimit,
ShellUpgrade,
ShellUpgrageSingleChange,
StageParameters,
TankAttributeChange,
TankAttributeChange_AttributeName,
TankAttributeChange_Modifier,
VisualChanges,
} from "@protos/blitz_static_tank_upgrade_single_stage";
import { times } from "lodash-es";
function patch(stage0: StageParameters, stage1: StageParameters) {
if (stage1.stage_number !== ++stage0.stage_number) {
throw new Error("Change stage number must be 1 greater than base");
}
for (const attribute1 of stage1.attributes) {
let value1: number;
switch (attribute1.modifier) {
case TankAttributeChange_Modifier.MODIFIER_OVERRIDE:
value1 = attribute1.value;
break;
case TankAttributeChange_Modifier.MODIFIER_MULTIPLY:
case TankAttributeChange_Modifier.MODIFIER_ADD:
const attribute0 = stage0.attributes.find(
(attribute0) =>
attribute0.attribute_name === attribute1.attribute_name
);
if (!attribute0) {
throw new Error(
`Missing attribute ${
TankAttributeChange_AttributeName[attribute1.attribute_name]
} (${attribute1.attribute_name}) to modify`
);
}
case TankAttributeChange_Modifier.MODIFIER_MULTIPLY: {
value1 = attribute0!.value! * attribute1.value;
break;
}
case TankAttributeChange_Modifier.MODIFIER_ADD: {
value1 = attribute0!.value! + attribute1.value;
break;
}
default:
throw new Error(
`Unhandled modified ${
TankAttributeChange_Modifier[attribute1.modifier]
}`
);
}
const attribute0 = TankAttributeChange.create({
modifier: TankAttributeChange_Modifier.MODIFIER_OVERRIDE,
attribute_name: attribute1.attribute_name,
value: value1,
});
const index0 = stage0.attributes.findIndex(
(attribute) => attribute.attribute_name === attribute1.attribute_name
);
if (index0 === -1) {
stage0.attributes.push(attribute0);
} else {
stage0.attributes[index0] = attribute0;
}
}
for (const penetrationGroupUpgrade1 of stage1.penetration_groups_upgrades) {
if (penetrationGroupUpgrade1.primary_armor.length > 0) {
throw new Error("Primary armor is not empty; implement this");
}
let penetrationGroupUpgrade0 = stage0.penetration_groups_upgrades.find(
(group) => group.tank_part === penetrationGroupUpgrade1.tank_part
);
if (!penetrationGroupUpgrade0) {
penetrationGroupUpgrade0 = PenetrationGroupUpgrade.create({
tank_part: penetrationGroupUpgrade1.tank_part,
});
stage0.penetration_groups_upgrades.push(penetrationGroupUpgrade0);
}
for (const penetrationGroup1 of penetrationGroupUpgrade1.penetration_groups) {
const penetrationGroup0 =
penetrationGroupUpgrade0.penetration_groups.find(
(baseGroup) => baseGroup.group_name === penetrationGroup1.group_name
);
if (penetrationGroup0) {
penetrationGroup0.common_data = penetrationGroup1.common_data;
penetrationGroup0.armor = penetrationGroup1.armor;
} else {
penetrationGroupUpgrade0.penetration_groups.push(
PenetrationGroup.create(penetrationGroup1)
);
}
}
}
if (stage1.modules_upgrades.length > 0) {
throw new Error("Modules upgrades not implemented");
}
for (const shellUpgrades1 of stage1.shells_upgrades) {
let shellUpgrades0 = stage0.shells_upgrades.find(
(baseShell) => baseShell.shell_id === shellUpgrades1.shell_id
);
if (shellUpgrades0) {
shellUpgrades0.shell_type = shellUpgrades1.shell_type;
for (const changedShellUpgrade of shellUpgrades1.changes) {
const shellUpgrade0 = shellUpgrades0.changes.find(
(baseShellUpgrade) =>
baseShellUpgrade.attribute_name ===
changedShellUpgrade.attribute_name
);
if (shellUpgrade0) {
shellUpgrade0.value = changedShellUpgrade.value;
} else {
shellUpgrades0.changes.push(
ShellUpgrageSingleChange.create(changedShellUpgrade)
);
}
}
shellUpgrades0.silver_price =
shellUpgrades1.silver_price === undefined
? undefined
: StandardSinglePrice.create(shellUpgrades1.silver_price);
} else {
stage0.shells_upgrades.push(ShellUpgrade.create(shellUpgrades1));
}
}
if (stage1.pump_reload_times.length > 0) {
throw new Error("Pump reload times not implemented");
}
if (stage1.pitch_limits_up.length > 0 && stage0.pitch_limits_up.length > 0) {
throw new Error("Pitch limits not implemented");
}
for (const pitchLimitUp1 of stage1.pitch_limits_up) {
stage0.pitch_limits_up.push(PitchLimit.create(pitchLimitUp1));
}
if (
stage1.pitch_limits_down.length > 0 &&
stage0.pitch_limits_down.length > 0
) {
throw new Error("Pitch limits not implemented");
}
for (const pitchLimitDown1 of stage1.pitch_limits_down) {
stage0.pitch_limits_down.push(PitchLimit.create(pitchLimitDown1));
}
for (const visualChange1 of stage1.visual_changes) {
const visualChange0 = stage0.visual_changes.find(
(baseVisualChange) =>
baseVisualChange.tank_part === visualChange1.tank_part
);
if (visualChange0) {
visualChange0.name = visualChange1.name;
} else {
stage0.visual_changes.push(VisualChanges.create(visualChange1));
}
}
}
export function aggregateStageParameters(
base: StageParameters,
stages: StageParameters[],
stage: number
) {
const stage0 = StageParameters.create();
patch(stage0, base);
/**
* Bug in Reforged: base stats are stage 1, so is the first upgrade. Manually
* setting it to stage 0 below and if the bug's been fixed, throw an error
* in dev mode to allow clean up in the future. Also, update the initial
* stage number to -1.
*/
if (stage0.stage_number === 0 && import.meta.env.DEV) {
throw new Error(
"Base stats are now stage 0. In-game bug fixed, please remove hack."
);
}
stage0.stage_number = 0;
times(stage, (index) => patch(stage0, stages[index]));
return stage0;
}
@@ -0,0 +1,52 @@
import {
ShellUpgrageSingleChange_AttributeName,
TankAttributeChange_AttributeName,
} from "@protos/blitz_static_tank_upgrade_single_stage";
export type CharacteristicOutput = number | string | null;
interface Characteristic {
value: (helpers: {
characteristic: (name: CharacteristicName) => CharacteristicOutput;
attribute: (name: TankAttributeChange_AttributeName) => number;
shell: (name: ShellUpgrageSingleChange_AttributeName) => number;
}) => CharacteristicOutput;
}
export type CharacteristicName = keyof typeof characteristics;
export const characteristics = {
gun_type: {
value({ attribute }) {
const isPump = attribute(
TankAttributeChange_AttributeName.ATTRIBUTE_NAME_IS_PUMP
);
if (isPump === 1) return "auto_reloader";
const clipSize = attribute(
TankAttributeChange_AttributeName.ATTRIBUTE_NAME_CLIP_SIZE
);
if (clipSize === 1) return "regular";
return "auto_loader";
},
},
damage: {
value({ shell }) {
return shell(
ShellUpgrageSingleChange_AttributeName.ATTRIBUTE_NAME_ARMOR_DAMAGE
);
},
},
dpm: {
value({ characteristic }) {
const damage = characteristic("damage");
return 1;
},
},
} satisfies Record<string, Characteristic>;
@@ -0,0 +1,25 @@
import type { CharacteristicName } from "./characteristics";
type CharacteristicsOrder = {
group: string;
order: CharacteristicName[];
}[];
export const characteristicsGroups = [
{
group: "firepower",
order: ["gun_type", "dpm"],
},
{
group: "maneuverability",
order: [],
},
{
group: "survivability",
order: [],
},
{
group: "miscellaneous",
order: [],
},
] satisfies CharacteristicsOrder;
@@ -0,0 +1,56 @@
import type {
ShellUpgrageSingleChange_AttributeName,
StageParameters,
TankAttributeChange_AttributeName,
} from "@protos/blitz_static_tank_upgrade_single_stage";
import {
characteristics,
type CharacteristicName,
type CharacteristicOutput,
} from "./characteristics";
export function renderCharacteristics(
parameters: StageParameters,
shellId: number
) {
const computed: Partial<Record<CharacteristicName, CharacteristicOutput>> =
{};
function characteristic(name: CharacteristicName) {
if (name in computed) return computed[name] as CharacteristicOutput;
throw new Error(`${name} not computed yet`);
}
function attribute(name: TankAttributeChange_AttributeName) {
const attribute = parameters.attributes.find(
(attribute) => attribute.attribute_name === name
);
if (!attribute) throw new Error(`Attribute ${name} not found`);
("");
return attribute.value;
}
function shell(name: ShellUpgrageSingleChange_AttributeName) {
const shell = parameters.shells_upgrades.find(
(shell) => shell.shell_id === name
);
if (!shell) throw new Error(`Shell ${name} not found`);
const attribute = shell.changes.find(
(change) => change.attribute_name === name
);
if (!attribute) throw new Error(`Shell attribute ${name} not found`);
return attribute.value;
}
for (const _name in characteristics) {
const name = _name as CharacteristicName;
const _characteristic = characteristics[name];
const value = _characteristic.value({ characteristic, attribute, shell });
}
}