mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-23 19:49:50 +02:00
feat: stat parity
This commit is contained in:
1 parent
b7558c33da
commit
09ba8663e6
6 files changed
+72
-57
No files matched your search
Vendored
+1
@@ -33,6 +33,7 @@
|
|||||||
"deburr",
|
"deburr",
|
||||||
"decalmask",
|
"decalmask",
|
||||||
"defence",
|
"defence",
|
||||||
|
"degressive",
|
||||||
"diacriticless",
|
"diacriticless",
|
||||||
"donotremove",
|
"donotremove",
|
||||||
"drei",
|
"drei",
|
||||||
|
|||||||
+11
-11
@@ -14,25 +14,25 @@ export function Miscellaneous() {
|
|||||||
const cooldownBooster = useTankopediaTemporary(
|
const cooldownBooster = useTankopediaTemporary(
|
||||||
(state) => state.cooldownBooster,
|
(state) => state.cooldownBooster,
|
||||||
);
|
);
|
||||||
const crew = useTankopediaTemporary((state) => state.crew);
|
const crewMastery = useTankopediaTemporary((state) => state.crewMastery);
|
||||||
const crewInput = useRef<HTMLInputElement>(null);
|
const crewInput = useRef<HTMLInputElement>(null);
|
||||||
const [crewDraft, setCrewDraft] = useState(crew);
|
const [crewMasteryDraft, setCrewMasteryDraft] = useState(crewMastery);
|
||||||
|
|
||||||
const debouncedApplyDraft = useMemo(
|
const debouncedApplyDraft = useMemo(
|
||||||
() =>
|
() =>
|
||||||
debounce((value) => {
|
debounce((value) => {
|
||||||
mutateTankopediaTemporary((draft) => {
|
mutateTankopediaTemporary((draft) => {
|
||||||
draft.crew = value;
|
draft.crewMastery = value;
|
||||||
});
|
});
|
||||||
}, 500),
|
}, 500),
|
||||||
[],
|
[],
|
||||||
);
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setCrewDraft(crew);
|
setCrewMasteryDraft(crewMastery);
|
||||||
if (!crewInput.current) return;
|
if (!crewInput.current) return;
|
||||||
crewInput.current.value = `${Math.round(crew * 100)}`;
|
crewInput.current.value = `${Math.round(crewMastery * 100)}`;
|
||||||
}, [crew]);
|
}, [crewMastery]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ConfigurationChildWrapper>
|
<ConfigurationChildWrapper>
|
||||||
@@ -91,18 +91,18 @@ export function Miscellaneous() {
|
|||||||
<TextField.Slot>Crew</TextField.Slot>
|
<TextField.Slot>Crew</TextField.Slot>
|
||||||
<TextField.Input
|
<TextField.Input
|
||||||
ref={crewInput}
|
ref={crewInput}
|
||||||
defaultValue={Math.round(crew * 100)}
|
defaultValue={Math.round(crewMastery * 100)}
|
||||||
style={{ textAlign: 'right' }}
|
style={{ textAlign: 'right' }}
|
||||||
onBlur={() => {
|
onBlur={() => {
|
||||||
const newValue = Number(crewInput.current!.value) / 100;
|
const newValue = Number(crewInput.current!.value) / 100;
|
||||||
|
|
||||||
if (isNaN(newValue)) {
|
if (isNaN(newValue)) {
|
||||||
crewInput.current!.value = `${Math.round(crew * 100)}`;
|
crewInput.current!.value = `${Math.round(crewMastery * 100)}`;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
mutateTankopediaTemporary((draft) => {
|
mutateTankopediaTemporary((draft) => {
|
||||||
draft.crew = clamp(newValue / 100, 0.5, 1);
|
draft.crewMastery = clamp(newValue / 100, 0.5, 1);
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
onKeyUp={(event) => {
|
onKeyUp={(event) => {
|
||||||
@@ -117,10 +117,10 @@ export function Miscellaneous() {
|
|||||||
<Slider
|
<Slider
|
||||||
min={50}
|
min={50}
|
||||||
max={100}
|
max={100}
|
||||||
value={[crewDraft * 100]}
|
value={[crewMasteryDraft * 100]}
|
||||||
style={{ width: '100%' }}
|
style={{ width: '100%' }}
|
||||||
onValueChange={([value]) => {
|
onValueChange={([value]) => {
|
||||||
setCrewDraft(value / 100);
|
setCrewMasteryDraft(value / 100);
|
||||||
debouncedApplyDraft(value / 100);
|
debouncedApplyDraft(value / 100);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -6,8 +6,10 @@ import { lerp } from 'three/src/math/MathUtils';
|
|||||||
import { isExplosive } from '../../../../../../core/blitz/isExplosive';
|
import { isExplosive } from '../../../../../../core/blitz/isExplosive';
|
||||||
import { resolveNearPenetration } from '../../../../../../core/blitz/resolveNearPenetration';
|
import { resolveNearPenetration } from '../../../../../../core/blitz/resolveNearPenetration';
|
||||||
import { coefficient } from '../../../../../../core/blitzkrieg/coefficient';
|
import { coefficient } from '../../../../../../core/blitzkrieg/coefficient';
|
||||||
|
import { degressiveStat } from '../../../../../../core/blitzkrieg/degressiveStat';
|
||||||
import { modelDefinitions } from '../../../../../../core/blitzkrieg/modelDefinitions';
|
import { modelDefinitions } from '../../../../../../core/blitzkrieg/modelDefinitions';
|
||||||
import { normalizeBoundingBox } from '../../../../../../core/blitzkrieg/normalizeBoundingBox';
|
import { normalizeBoundingBox } from '../../../../../../core/blitzkrieg/normalizeBoundingBox';
|
||||||
|
import { progressiveStat } from '../../../../../../core/blitzkrieg/progressiveStat';
|
||||||
import { resolveDpm } from '../../../../../../core/blitzkrieg/resolveDpm';
|
import { resolveDpm } from '../../../../../../core/blitzkrieg/resolveDpm';
|
||||||
import { sum } from '../../../../../../core/blitzkrieg/sum';
|
import { sum } from '../../../../../../core/blitzkrieg/sum';
|
||||||
import {
|
import {
|
||||||
@@ -29,7 +31,15 @@ export function Characteristics() {
|
|||||||
const { tank, turret, gun, engine, track, shell } = useDuel(
|
const { tank, turret, gun, engine, track, shell } = useDuel(
|
||||||
(state) => state.protagonist!,
|
(state) => state.protagonist!,
|
||||||
);
|
);
|
||||||
const crew = useTankopediaTemporary((state) => state.crew);
|
const provisions = useProvisions();
|
||||||
|
const crewMastery = useTankopediaTemporary((state) => state.crewMastery);
|
||||||
|
const provisionCrewBonus = provisions.reduce(
|
||||||
|
(total, provision) =>
|
||||||
|
provision.crew ? total + provision.crew / 100 : total,
|
||||||
|
0,
|
||||||
|
);
|
||||||
|
const commanderMastery = crewMastery + provisionCrewBonus;
|
||||||
|
const crewMemberMastery = commanderMastery * 1.1;
|
||||||
const stockEngine = tank.engines[0];
|
const stockEngine = tank.engines[0];
|
||||||
const stockTrack = tank.tracks[0];
|
const stockTrack = tank.tracks[0];
|
||||||
const stockTurret = tank.turrets[0];
|
const stockTurret = tank.turrets[0];
|
||||||
@@ -53,7 +63,6 @@ export function Characteristics() {
|
|||||||
stockTurret.weight +
|
stockTurret.weight +
|
||||||
stockGun.weight;
|
stockGun.weight;
|
||||||
const [penetrationDistance, setPenetrationDistance] = useState(250);
|
const [penetrationDistance, setPenetrationDistance] = useState(250);
|
||||||
const provisions = useProvisions();
|
|
||||||
const camouflage = useTankopediaTemporary((state) => state.camouflage);
|
const camouflage = useTankopediaTemporary((state) => state.camouflage);
|
||||||
const hasRammer = useEquipment(100);
|
const hasRammer = useEquipment(100);
|
||||||
const hasCalibratedShells = useEquipment(103);
|
const hasCalibratedShells = useEquipment(103);
|
||||||
@@ -89,10 +98,10 @@ export function Characteristics() {
|
|||||||
[hasEnhancedSandbagArmor, 0.06],
|
[hasEnhancedSandbagArmor, 0.06],
|
||||||
[hasImprovedAssembly, 0.06],
|
[hasImprovedAssembly, 0.06],
|
||||||
);
|
);
|
||||||
const reloadCoefficient = coefficient(
|
const reloadCoefficient =
|
||||||
[hasRammer, -0.07],
|
(coefficient([hasRammer, -0.07]) *
|
||||||
[hasAdrenaline && gun.type === 'regular', -0.2],
|
coefficient([true, degressiveStat(crewMemberMastery)])) /
|
||||||
);
|
coefficient([hasAdrenaline && gun.type === 'regular', 0.2]);
|
||||||
const penetrationCoefficient = coefficient([
|
const penetrationCoefficient = coefficient([
|
||||||
hasCalibratedShells,
|
hasCalibratedShells,
|
||||||
isExplosive(shell.type) ? 0.1 : 0.05,
|
isExplosive(shell.type) ? 0.1 : 0.05,
|
||||||
@@ -110,15 +119,18 @@ export function Characteristics() {
|
|||||||
hasSupercharger,
|
hasSupercharger,
|
||||||
-0.5,
|
-0.5,
|
||||||
]);
|
]);
|
||||||
const aimTimeCoefficient = coefficient(
|
const aimTimeCoefficient =
|
||||||
[hasEnhancedGunLayingDrive, -0.1],
|
coefficient(
|
||||||
[hasReticleCalibration, -0.4],
|
[hasEnhancedGunLayingDrive, -0.1],
|
||||||
[hasVerticalStabilizer, -0.15],
|
[hasReticleCalibration, -0.4],
|
||||||
);
|
) * coefficient([true, degressiveStat(crewMemberMastery)]);
|
||||||
const dispersionCoefficient = coefficient(
|
const dispersionStillCoefficient =
|
||||||
[hasRefinedGun, -0.1],
|
coefficient([hasRefinedGun, -0.1], [hasReticleCalibration, -0.4]) *
|
||||||
[hasReticleCalibration, -0.4],
|
coefficient([true, degressiveStat(crewMemberMastery)]);
|
||||||
);
|
const dispersionMovingCoefficient = coefficient([
|
||||||
|
hasVerticalStabilizer,
|
||||||
|
-0.15,
|
||||||
|
]);
|
||||||
const enginePowerCoefficient = coefficient(
|
const enginePowerCoefficient = coefficient(
|
||||||
[
|
[
|
||||||
hasEngineAccelerator && (tank.type === 'light' || tank.type === 'medium'),
|
hasEngineAccelerator && (tank.type === 'light' || tank.type === 'medium'),
|
||||||
@@ -136,19 +148,20 @@ export function Characteristics() {
|
|||||||
[hasGearOil, 0.03],
|
[hasGearOil, 0.03],
|
||||||
[hasImprovedGearOil, 0.06],
|
[hasImprovedGearOil, 0.06],
|
||||||
);
|
);
|
||||||
const turretTraverseCoefficient = coefficient(
|
const turretTraverseCoefficient =
|
||||||
[hasStandardFuel, 0.03],
|
coefficient([hasStandardFuel, 0.03], [hasImprovedFuel, 0.1]) *
|
||||||
[hasImprovedFuel, 0.1],
|
coefficient([true, progressiveStat(crewMemberMastery)]);
|
||||||
);
|
const hullTraverseCoefficient =
|
||||||
const hullTraverseCoefficient = coefficient(
|
coefficient(
|
||||||
[hasImprovedControl, 0.1],
|
[hasImprovedControl, 0.1],
|
||||||
[hasImprovedEnginePowerBoost, 0.05],
|
[hasImprovedEnginePowerBoost, 0.05],
|
||||||
);
|
) * coefficient([true, progressiveStat(crewMemberMastery)]);
|
||||||
const resistanceCoefficient = coefficient([hasImprovedSuspension, -0.25]);
|
const resistanceCoefficient = coefficient([hasImprovedSuspension, -0.25]);
|
||||||
const viewRangeCoefficient = coefficient([
|
const viewRangeCoefficient =
|
||||||
hasImprovedOptics,
|
coefficient([
|
||||||
tank.type === 'tankDestroyer' ? 0.05 : tank.type === 'heavy' ? 0.07 : 0.1,
|
hasImprovedOptics,
|
||||||
]);
|
tank.type === 'tankDestroyer' ? 0.05 : tank.type === 'heavy' ? 0.07 : 0.1,
|
||||||
|
]) * coefficient([true, progressiveStat(commanderMastery)]);
|
||||||
const fireChanceCoefficient = coefficient([hasProtectiveKit, -0.2]);
|
const fireChanceCoefficient = coefficient([hasProtectiveKit, -0.2]);
|
||||||
|
|
||||||
const speedForwardsSum = sum(
|
const speedForwardsSum = sum(
|
||||||
@@ -199,11 +212,6 @@ export function Characteristics() {
|
|||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
const provisionCrewBonus = provisions.reduce(
|
|
||||||
(total, provision) =>
|
|
||||||
provision.crew ? total + provision.crew / 100 : total,
|
|
||||||
0,
|
|
||||||
);
|
|
||||||
const resolvedEnginePower = engine.power * enginePowerCoefficient;
|
const resolvedEnginePower = engine.power * enginePowerCoefficient;
|
||||||
const dpm = resolveDpm(
|
const dpm = resolveDpm(
|
||||||
gun,
|
gun,
|
||||||
@@ -363,7 +371,7 @@ export function Characteristics() {
|
|||||||
<InfoWithDelta name="Module damage" unit="hp" decimals={0}>
|
<InfoWithDelta name="Module damage" unit="hp" decimals={0}>
|
||||||
{shell.damage.module * damageCoefficient}
|
{shell.damage.module * damageCoefficient}
|
||||||
</InfoWithDelta>
|
</InfoWithDelta>
|
||||||
<InfoWithDelta name="Shell velocity" unit="m/s">
|
<InfoWithDelta name="Shell velocity" unit="m/s" decimals={0}>
|
||||||
{shell.speed * shellVelocityCoefficient}
|
{shell.speed * shellVelocityCoefficient}
|
||||||
</InfoWithDelta>
|
</InfoWithDelta>
|
||||||
<InfoWithDelta
|
<InfoWithDelta
|
||||||
@@ -382,7 +390,7 @@ export function Characteristics() {
|
|||||||
unit="m"
|
unit="m"
|
||||||
deltaType="lowerIsBetter"
|
deltaType="lowerIsBetter"
|
||||||
>
|
>
|
||||||
{gun.dispersion.base * dispersionCoefficient}
|
{gun.dispersion.base * dispersionStillCoefficient}
|
||||||
</InfoWithDelta>
|
</InfoWithDelta>
|
||||||
<InfoWithDelta
|
<InfoWithDelta
|
||||||
prefix="+ "
|
prefix="+ "
|
||||||
@@ -392,7 +400,7 @@ export function Characteristics() {
|
|||||||
unit="s"
|
unit="s"
|
||||||
deltaType="lowerIsBetter"
|
deltaType="lowerIsBetter"
|
||||||
>
|
>
|
||||||
{track.dispersion.move * dispersionCoefficient}
|
{track.dispersion.move * dispersionMovingCoefficient}
|
||||||
</InfoWithDelta>
|
</InfoWithDelta>
|
||||||
<InfoWithDelta
|
<InfoWithDelta
|
||||||
decimals={3}
|
decimals={3}
|
||||||
@@ -402,7 +410,7 @@ export function Characteristics() {
|
|||||||
unit="°"
|
unit="°"
|
||||||
deltaType="lowerIsBetter"
|
deltaType="lowerIsBetter"
|
||||||
>
|
>
|
||||||
{track.dispersion.traverse * dispersionCoefficient}
|
{track.dispersion.traverse * dispersionMovingCoefficient}
|
||||||
</InfoWithDelta>
|
</InfoWithDelta>
|
||||||
<InfoWithDelta
|
<InfoWithDelta
|
||||||
decimals={3}
|
decimals={3}
|
||||||
@@ -412,7 +420,7 @@ export function Characteristics() {
|
|||||||
unit="°"
|
unit="°"
|
||||||
deltaType="lowerIsBetter"
|
deltaType="lowerIsBetter"
|
||||||
>
|
>
|
||||||
{gun.dispersion.traverse * dispersionCoefficient}
|
{gun.dispersion.traverse * dispersionMovingCoefficient}
|
||||||
</InfoWithDelta>
|
</InfoWithDelta>
|
||||||
<InfoWithDelta
|
<InfoWithDelta
|
||||||
decimals={3}
|
decimals={3}
|
||||||
@@ -422,17 +430,17 @@ export function Characteristics() {
|
|||||||
unit="m"
|
unit="m"
|
||||||
deltaType="lowerIsBetter"
|
deltaType="lowerIsBetter"
|
||||||
>
|
>
|
||||||
{gun.dispersion.shot * dispersionCoefficient}
|
{gun.dispersion.shot * dispersionMovingCoefficient}
|
||||||
</InfoWithDelta>
|
</InfoWithDelta>
|
||||||
<InfoWithDelta
|
<InfoWithDelta
|
||||||
decimals={3}
|
decimals={1}
|
||||||
prefix="x "
|
prefix="x "
|
||||||
indent
|
indent
|
||||||
name="Gun damaged"
|
name="Gun damaged"
|
||||||
unit="scalar"
|
unit="scalar"
|
||||||
deltaType="lowerIsBetter"
|
deltaType="lowerIsBetter"
|
||||||
>
|
>
|
||||||
{gun.dispersion.damaged * dispersionCoefficient}
|
{gun.dispersion.damaged * dispersionMovingCoefficient}
|
||||||
</InfoWithDelta>
|
</InfoWithDelta>
|
||||||
<Info name="Gun flexibility" unit="°" />
|
<Info name="Gun flexibility" unit="°" />
|
||||||
<InfoWithDelta decimals={1} indent name="Depression">
|
<InfoWithDelta decimals={1} indent name="Depression">
|
||||||
@@ -549,7 +557,7 @@ export function Characteristics() {
|
|||||||
<InfoWithDelta name="Fire chance" unit="%" deltaType="lowerIsBetter">
|
<InfoWithDelta name="Fire chance" unit="%" deltaType="lowerIsBetter">
|
||||||
{Math.round(engine.fireChance * fireChanceCoefficient * 100)}
|
{Math.round(engine.fireChance * fireChanceCoefficient * 100)}
|
||||||
</InfoWithDelta>
|
</InfoWithDelta>
|
||||||
<InfoWithDelta name="View range" unit="m">
|
<InfoWithDelta name="View range" unit="m" decimals={0}>
|
||||||
{turret.viewRange * viewRangeCoefficient}
|
{turret.viewRange * viewRangeCoefficient}
|
||||||
</InfoWithDelta>
|
</InfoWithDelta>
|
||||||
<Info name="Camouflage" unit="%" />
|
<Info name="Camouflage" unit="%" />
|
||||||
@@ -590,9 +598,9 @@ export function Characteristics() {
|
|||||||
unit="%"
|
unit="%"
|
||||||
decimals={0}
|
decimals={0}
|
||||||
>
|
>
|
||||||
{(crew + provisionCrewBonus) *
|
{(member.type === 'commander'
|
||||||
(member.type === 'commander' ? 1 : 1.1) *
|
? commanderMastery
|
||||||
100}
|
: crewMemberMastery) * 100}
|
||||||
</InfoWithDelta>
|
</InfoWithDelta>
|
||||||
{member.substitute && (
|
{member.substitute && (
|
||||||
<Info
|
<Info
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
export function degressiveStat(crew: number) {
|
||||||
|
return 0.875 / (0.00375 * 100 * crew + 0.5) - 1;
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
export function progressiveStat(crew: number) {
|
||||||
|
return (0.00375 * 100 * crew + 0.5) / 0.875 - 1;
|
||||||
|
}
|
||||||
@@ -67,7 +67,7 @@ interface TankopediaTemporary {
|
|||||||
equipmentMatrix: EquipmentMatrix;
|
equipmentMatrix: EquipmentMatrix;
|
||||||
mode: TankopediaMode;
|
mode: TankopediaMode;
|
||||||
consumables: number[];
|
consumables: number[];
|
||||||
crew: number;
|
crewMastery: number;
|
||||||
provisions: number[];
|
provisions: number[];
|
||||||
camouflage: boolean;
|
camouflage: boolean;
|
||||||
cooldownBooster: number;
|
cooldownBooster: number;
|
||||||
@@ -176,7 +176,7 @@ export const useTankopediaTemporary = create<TankopediaTemporary>()(
|
|||||||
[0, 0, 0],
|
[0, 0, 0],
|
||||||
[0, 0, 0],
|
[0, 0, 0],
|
||||||
],
|
],
|
||||||
crew: 0.75,
|
crewMastery: 0.75,
|
||||||
mode: 'model',
|
mode: 'model',
|
||||||
consumables: [],
|
consumables: [],
|
||||||
provisions: [],
|
provisions: [],
|
||||||
|
|||||||
Reference in new issue
Block a user