hull traverse speeds

This commit is contained in:
tresabhi committed 2026-10-11 01:36:34 -05:00
1 parent e7708ce01b
commit e1bc11644d
8 files changed
+208 -78

No files matched your search

+5
View File
@@ -66,6 +66,7 @@
"azimuth_right": "Azimuth right", "azimuth_right": "Azimuth right",
"speed_forward": "Speed forward", "speed_forward": "Speed forward",
"speed_backward": "Speed backward", "speed_backward": "Speed backward",
"speeds": "Speeds",
"engine_power": "Engine power", "engine_power": "Engine power",
"brake_force": "Brake force", "brake_force": "Brake force",
"weight": "Weight", "weight": "Weight",
@@ -79,6 +80,10 @@
"medium_terrain_coefficient_raw": "Medium", "medium_terrain_coefficient_raw": "Medium",
"soft_terrain_coefficient_raw": "Soft", "soft_terrain_coefficient_raw": "Soft",
"hull_traverse_speed": "Hull traverse speed", "hull_traverse_speed": "Hull traverse speed",
"hull_traverse_speeds": "Hull traverse speeds",
"hull_traverse_speed_hard": "Hard",
"hull_traverse_speed_medium": "Medium",
"hull_traverse_speed_soft": "Soft",
"turret_traverse_speed": "Turret traverse speed", "turret_traverse_speed": "Turret traverse speed",
"gun_traverse_speed": "Gun traverse speed", "gun_traverse_speed": "Gun traverse speed",
"health": "Health", "health": "Health",
+55 -53
View File
@@ -5,54 +5,12 @@ import {
unionBoundingBox, unionBoundingBox,
} from "@blitzkit/core"; } from "@blitzkit/core";
import { ShellType, TankClass } from "@blitzkit/protos"; import { ShellType, TankClass } from "@blitzkit/protos";
import { hullTraverseSpeed } from "../tankopedia/hullTraverseSpeed";
import { rawTerrainCoefficient } from "../tankopedia/rawTerrainCoefficient";
import { import {
CharacteristicType, CharacteristicType,
type Characteristic, type Characteristic,
type CharacteristicContext,
} from "../types/characteristics"; } from "../types/characteristics";
import { rawTerrainCoefficient } from "../tankopedia/rawTerrainCoefficient";
function intraClipCoefficient({
script,
}: Pick<CharacteristicContext, "script">) {
let coefficient = 1;
script("protagonist", "NewAutoloader", (effect) => {
coefficient *= effect.clipReloadTimeFactor;
});
return coefficient;
}
function aimTimeCoefficient({ script }: Pick<CharacteristicContext, "script">) {
let coefficient = 1;
script("protagonist", "miscAttrs/gunAimingTimeFactor", (effect) => {
coefficient += effect.bonusValues!.percent / 100;
});
script("protagonist", "FireControlSystem", (effect) => {
coefficient *= effect.aimingTimeFactor;
});
return coefficient;
}
function dispersionCoefficient({
script,
}: Pick<CharacteristicContext, "script">) {
let coefficient = 1;
script("protagonist", "miscAttrs/shotDispersionAngleFactor", (effect) => {
coefficient += effect.bonusValues!.percent / 100;
});
script("protagonist", "FireControlSystem", (effect) => {
coefficient *= effect.shotDispersionAngleFactor;
});
return coefficient;
}
export const characteristics = { export const characteristics = {
gun_type: { gun_type: {
@@ -490,10 +448,20 @@ export const characteristics = {
dispersion: { dispersion: {
type: CharacteristicType.Number, type: CharacteristicType.Number,
compute({ gun, degressive, script }) { compute({ gun, degressive, script }) {
let coefficient = 1;
script("protagonist", "miscAttrs/shotDispersionAngleFactor", (effect) => {
coefficient += effect.bonusValues!.percent / 100;
});
script("protagonist", "FireControlSystem", (effect) => {
coefficient *= effect.shotDispersionAngleFactor;
});
return ( return (
gun.dispersion_base * gun.dispersion_base *
degressive("gunner") * degressive("gunner") *
dispersionCoefficient({ script }) coefficient
); );
}, },
}, },
@@ -527,8 +495,9 @@ export const characteristics = {
gun_frontal_depression: { gun_frontal_depression: {
type: CharacteristicType.Number, type: CharacteristicType.Number,
should_render({ state, turret, gun }) { should_render({ state, turret, gun }) {
return state.model.turrets[turret.id].guns[gun.id].pitch!.front !== return (
undefined; state.model.turrets[turret.id].guns[gun.id].pitch!.front !== undefined
);
}, },
compute({ state, turret, gun }) { compute({ state, turret, gun }) {
return state.model.turrets[turret.id].guns[gun.id].pitch!.front!.max; return state.model.turrets[turret.id].guns[gun.id].pitch!.front!.max;
@@ -538,8 +507,9 @@ export const characteristics = {
gun_frontal_elevation: { gun_frontal_elevation: {
type: CharacteristicType.Number, type: CharacteristicType.Number,
should_render({ state, turret, gun }) { should_render({ state, turret, gun }) {
return state.model.turrets[turret.id].guns[gun.id].pitch!.front !== return (
undefined; state.model.turrets[turret.id].guns[gun.id].pitch!.front !== undefined
);
}, },
compute({ state, turret, gun }) { compute({ state, turret, gun }) {
return -state.model.turrets[turret.id].guns[gun.id].pitch!.front!.min; return -state.model.turrets[turret.id].guns[gun.id].pitch!.front!.min;
@@ -549,8 +519,9 @@ export const characteristics = {
gun_rear_depression: { gun_rear_depression: {
type: CharacteristicType.Number, type: CharacteristicType.Number,
should_render({ state, turret, gun }) { should_render({ state, turret, gun }) {
return state.model.turrets[turret.id].guns[gun.id].pitch!.back !== return (
undefined; state.model.turrets[turret.id].guns[gun.id].pitch!.back !== undefined
);
}, },
compute({ state, turret, gun }) { compute({ state, turret, gun }) {
return state.model.turrets[turret.id].guns[gun.id].pitch!.back!.max; return state.model.turrets[turret.id].guns[gun.id].pitch!.back!.max;
@@ -560,8 +531,9 @@ export const characteristics = {
gun_rear_elevation: { gun_rear_elevation: {
type: CharacteristicType.Number, type: CharacteristicType.Number,
should_render({ state, turret, gun }) { should_render({ state, turret, gun }) {
return state.model.turrets[turret.id].guns[gun.id].pitch!.back !== return (
undefined; state.model.turrets[turret.id].guns[gun.id].pitch!.back !== undefined
);
}, },
compute({ state, turret, gun }) { compute({ state, turret, gun }) {
return -state.model.turrets[turret.id].guns[gun.id].pitch!.back!.min; return -state.model.turrets[turret.id].guns[gun.id].pitch!.back!.min;
@@ -690,6 +662,36 @@ export const characteristics = {
}, },
}, },
hull_traverse_speed_hard: {
type: CharacteristicType.Number,
compute(context): number {
return hullTraverseSpeed(
context.characteristic("hard_terrain_coefficient_raw") as number,
context,
);
},
},
hull_traverse_speed_medium: {
type: CharacteristicType.Number,
compute(context): number {
return hullTraverseSpeed(
context.characteristic("medium_terrain_coefficient_raw") as number,
context,
);
},
},
hull_traverse_speed_soft: {
type: CharacteristicType.Number,
compute(context): number {
return hullTraverseSpeed(
context.characteristic("soft_terrain_coefficient_raw") as number,
context,
);
},
},
turret_traverse_speed: { turret_traverse_speed: {
type: CharacteristicType.Number, type: CharacteristicType.Number,
compute({ turret, progressive }) { compute({ turret, progressive }) {
@@ -155,8 +155,9 @@ export const characteristicsGroups: CharacteristicsGroup[] = [
name: "maneuverability", name: "maneuverability",
// render: CharacteristicsGroupRender.Statistical, // render: CharacteristicsGroupRender.Statistical,
order: [ order: [
{ name: "speed_forward", units: "km_h" }, { label: "speeds" },
{ name: "speed_backward", units: "km_h" }, { name: "speed_forward", units: "km_h", indent: true },
{ name: "speed_backward", units: "km_h", indent: true },
{ name: "weight", decimals: 1, units: "t" }, { name: "weight", decimals: 1, units: "t" },
{ name: "engine_power", units: "bhp" }, { name: "engine_power", units: "bhp" },
@@ -173,7 +174,10 @@ export const characteristicsGroups: CharacteristicsGroup[] = [
{ name: "medium_terrain_coefficient_raw", decimals: 2, indent: true }, { name: "medium_terrain_coefficient_raw", decimals: 2, indent: true },
{ name: "soft_terrain_coefficient_raw", decimals: 2, indent: true }, { name: "soft_terrain_coefficient_raw", decimals: 2, indent: true },
{ name: "hull_traverse_speed", units: "deg_s" }, { label: "hull_traverse_speeds" },
{ name: "hull_traverse_speed_hard", units: "deg_s", indent: true },
{ name: "hull_traverse_speed_medium", units: "deg_s", indent: true },
{ name: "hull_traverse_speed_soft", units: "deg_s", indent: true },
{ name: "turret_traverse_speed", units: "deg_s" }, { name: "turret_traverse_speed", units: "deg_s" },
{ name: "gun_traverse_speed", units: "deg_s" }, { name: "gun_traverse_speed", units: "deg_s" },
@@ -91,19 +91,17 @@ export function computeCharacteristics(
} }
} }
const protagonist = states.protagonist; let provisionCrewBonus = 0;
const protagonistEquipmentPreset = equipment.presets[tank.equipment_preset]; script("protagonist", "Stimulator", (effect) => {
const hasImprovedVentilation = Object.entries(protagonist.equipment).some( provisionCrewBonus += (effect.bonusValues?.crewLevelIncrease ?? 0) / 100;
([index, choice]) => });
protagonistEquipmentPreset.slots[Number(index)]?.options[choice] === 102,
); script("protagonist", "StaticAdditiveDevice", (effect) => {
const provisionCrewBonus = if (effect.attribute !== "miscAttrs/crewLevelIncrease") return;
protagonist.provisions.reduce(
(total, id) => provisionCrewBonus += (effect.bonusValues?.value ?? 0) / 100;
total + });
(scripts.provisions[id]?.bonusValues?.crewLevelIncrease ?? 0) / 100,
0,
) + (hasImprovedVentilation ? 0.08 : 0);
const commanderMastery = 1 + provisionCrewBonus; const commanderMastery = 1 + provisionCrewBonus;
const crewMastery = { const crewMastery = {
commander: commanderMastery, commander: commanderMastery,
+6 -3
View File
@@ -79,6 +79,7 @@ export enum TankopediaRelativeAgainst {
export interface TankEnvironment { export interface TankEnvironment {
equalize: boolean; equalize: boolean;
distance: number; distance: number;
skills: Record<string, number>;
} }
interface Tankopedia { interface Tankopedia {
@@ -91,7 +92,6 @@ interface Tankopedia {
modelRequested: boolean; modelRequested: boolean;
shot?: Shot; shot?: Shot;
skills: Record<string, number>;
relativeAgainst: TankopediaRelativeAgainst; relativeAgainst: TankopediaRelativeAgainst;
editStatic: boolean; editStatic: boolean;
highlightArmor?: { highlightArmor?: {
@@ -127,13 +127,16 @@ export const Tankopedia = new Soapstone<Tankopedia, [TankDefinition]>(
antagonist: createTankState(tank), antagonist: createTankState(tank),
model: models.models[tank.id], model: models.models[tank.id],
environment: { equalize: false, distance: 0 }, environment: {
equalize: false,
distance: 0,
skills: createDefaultSkills(skills),
},
modelRequested: false, modelRequested: false,
relativeAgainst: TankopediaRelativeAgainst.Class, relativeAgainst: TankopediaRelativeAgainst.Class,
editStatic: false, editStatic: false,
skills: createDefaultSkills(skills),
xpMultiplier: 1, xpMultiplier: 1,
requestedDisplay: TankopediaDisplay.Model, requestedDisplay: TankopediaDisplay.Model,
display: TankopediaDisplay.Model, display: TankopediaDisplay.Model,
@@ -0,0 +1,109 @@
import type {
CharacteristicContext,
CharacteristicScript,
} from "../types/characteristics";
import { tankClassToBlitzTankClass } from "./tankClass";
function hullTraverseEnginePowerCoefficient(
tank: TankDefinition,
script: CharacteristicScript,
) {
let coefficient = 1;
const enginePowerPercentage = tankClassToBlitzTankClass[tank.class];
script("protagonist", "RecycledEngine", (effect) => {
coefficient +=
(effect.enginePowerPercentageBonus?.[enginePowerPercentage] ?? 0) / 100;
});
script("protagonist", "Afterburning", (effect) => {
coefficient += (effect.bonusValues?.enginePowerIncrease ?? 0) / 100;
});
script("protagonist", "ImprovedAfterburning", (effect) => {
coefficient += (effect.enginePowerIncrease ?? 1) - 1;
});
script("protagonist", "Fuel", (effect) => {
coefficient += (effect.bonusValues?.enginePowerIncrease ?? 0) / 100;
});
script("protagonist", "GearOil", (effect) => {
coefficient += (effect.bonusValues?.enginePowerIncrease ?? 0) / 100;
});
script("protagonist", "AttributesModifier", (effect) => {
coefficient *= effect.attributes?.enginePowerFactor ?? 1;
});
return coefficient;
}
function hullTraverseRotationCoefficient(
driverCoefficient: number,
virtuosoSkill: number,
script: CharacteristicScript,
) {
let coefficient = 1 + virtuosoSkill / 100;
let rotationSpeedFactor = 1;
script("protagonist", "StaticPhysicsAttrsModifier", (effect) => {
coefficient += (effect.bonusPercentage?.rotationSpeedFactor ?? 0) / 100;
});
script("protagonist", "ImprovedAfterburning", (effect) => {
rotationSpeedFactor *= effect.rotationSpeedFactor ?? 1;
});
script("protagonist", "AfterburnerAbility", (effect) => {
rotationSpeedFactor *= effect.bonusValues?.rotationSpeedFactor ?? 1;
});
return driverCoefficient * coefficient * rotationSpeedFactor;
}
export function hullTraverseSpeed(
rawTerrainResistance: number,
context: CharacteristicContext,
) {
const {
tank,
engine,
track,
turret,
gun,
progressive,
script,
environment,
} = context;
const terrainResistance = track.resistance_hard;
const stockEngine = tank.engines[0];
const stockTrack = tank.tracks[0];
const stockTurret = tank.turrets[0];
const stockGun = stockTurret.guns[0];
const stockWeight =
tank.weight +
stockEngine.weight +
stockTrack.weight +
stockTurret.weight +
stockGun.weight;
const weight =
tank.weight + engine.weight + track.weight + turret.weight + gun.weight;
const enginePower =
(engine.power * hullTraverseEnginePowerCoefficient(tank, script)) /
stockEngine.power;
const rotationSpeed = hullTraverseRotationCoefficient(
progressive("driver"),
environment.skills.virtuoso ?? 0,
script,
);
return (
enginePower *
track.traverse_speed *
rotationSpeed *
(terrainResistance / rawTerrainResistance) *
(stockWeight / weight)
);
}
@@ -6,17 +6,17 @@ export function rawTerrainCoefficient(
driverCoefficient: number, driverCoefficient: number,
script: CharacteristicScript, script: CharacteristicScript,
) { ) {
let passabilityIncrease = 0; let passabilityFactor = 1;
let terrainResistanceFactor = 1; let terrainResistanceFactor = 1;
script("protagonist", "Grousers", (effect) => { script("protagonist", "Grousers", (effect) => {
passabilityIncrease += passabilityFactor *=
(effect.bonusPercentage?.[passabilityAttribute] ?? 0) / 100; 1 - (effect.bonusPercentage?.[passabilityAttribute] ?? 0) / 100;
}); });
script("protagonist", "AttributesModifier", (effect) => { script("protagonist", "AttributesModifier", (effect) => {
passabilityIncrease += passabilityFactor *=
(effect.attributes?.[passabilityAttribute] ?? 0) / 100; 1 - (effect.attributes?.[passabilityAttribute] ?? 0) / 100;
}); });
script("protagonist", "AfterburnerAbility", (effect) => { script("protagonist", "AfterburnerAbility", (effect) => {
@@ -25,7 +25,7 @@ export function rawTerrainCoefficient(
return ( return (
resistance * resistance *
(1 - passabilityIncrease) * passabilityFactor *
terrainResistanceFactor * terrainResistanceFactor *
driverCoefficient driverCoefficient
); );
@@ -0,0 +1,9 @@
import type { BlitzTankClass } from "@blitzkit/core";
import { TankClass } from "@blitzkit/protos";
export const tankClassToBlitzTankClass: Record<TankClass, BlitzTankClass> = {
[TankClass.TANK_CLASS_LIGHT]: "lightTank",
[TankClass.TANK_CLASS_MEDIUM]: "mediumTank",
[TankClass.TANK_CLASS_HEAVY]: "heavyTank",
[TankClass.TANK_CLASS_TANK_DESTROYER]: "AT-SPG",
};