mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-24 12:09:51 +02:00
fix: stat parity with game
This commit is contained in:
1 parent
8d32c7ce23
commit
7f796c5ec1
3 files changed
+55
-67
No files matched your search
@@ -12,7 +12,6 @@ import { debounce } from 'lodash';
|
|||||||
import { Fragment, use, useEffect, useRef, useState } from 'react';
|
import { Fragment, use, useEffect, useRef, useState } from 'react';
|
||||||
import { lerp } from 'three/src/math/MathUtils';
|
import { lerp } from 'three/src/math/MathUtils';
|
||||||
import { Ad, AdType } from '../../../../../../components/Ad';
|
import { Ad, AdType } from '../../../../../../components/Ad';
|
||||||
import { Link } from '../../../../../../components/Link';
|
|
||||||
import { applyPitchYawLimits } from '../../../../../../core/blitz/applyPitchYawLimits';
|
import { applyPitchYawLimits } from '../../../../../../core/blitz/applyPitchYawLimits';
|
||||||
import { isExplosive } from '../../../../../../core/blitz/isExplosive';
|
import { isExplosive } from '../../../../../../core/blitz/isExplosive';
|
||||||
import { resolvePenetrationCoefficient } from '../../../../../../core/blitz/resolvePenetrationCoefficient';
|
import { resolvePenetrationCoefficient } from '../../../../../../core/blitz/resolvePenetrationCoefficient';
|
||||||
@@ -179,27 +178,14 @@ export function Characteristics() {
|
|||||||
{stats.dpm}
|
{stats.dpm}
|
||||||
</InfoWithDelta>
|
</InfoWithDelta>
|
||||||
{gun.type === 'autoReloader' && (
|
{gun.type === 'autoReloader' && (
|
||||||
<>
|
<InfoWithDelta
|
||||||
<InfoWithDelta decimals={0} indent name="Maximum" unit="hp / min">
|
decimals={0}
|
||||||
{stats.dpmMaximum!}
|
indent
|
||||||
</InfoWithDelta>
|
name="Effective at 60s"
|
||||||
<InfoWithDelta
|
unit="hp / min"
|
||||||
decimals={0}
|
>
|
||||||
indent
|
{stats.dpmEffective!}
|
||||||
name="Effective at 60s"
|
</InfoWithDelta>
|
||||||
unit="hp / min"
|
|
||||||
>
|
|
||||||
{stats.dpmEffective!}
|
|
||||||
</InfoWithDelta>
|
|
||||||
<Info
|
|
||||||
indent
|
|
||||||
name={
|
|
||||||
<Link target="_blank" href="/docs/guide/dpm">
|
|
||||||
What's the difference?
|
|
||||||
</Link>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</>
|
|
||||||
)}
|
)}
|
||||||
{gun.type !== 'regular' && (
|
{gun.type !== 'regular' && (
|
||||||
<InfoWithDelta name="Shells">{stats.shells}</InfoWithDelta>
|
<InfoWithDelta name="Shells">{stats.shells}</InfoWithDelta>
|
||||||
@@ -477,15 +463,18 @@ export function Characteristics() {
|
|||||||
>
|
>
|
||||||
{(member.type === 'commander'
|
{(member.type === 'commander'
|
||||||
? commanderMastery
|
? commanderMastery
|
||||||
: crewMemberMastery) * 100}
|
: commanderMastery * 1.1) * 100}
|
||||||
</InfoWithDelta>
|
</InfoWithDelta>
|
||||||
|
|
||||||
{member.substitute && (
|
{member.substitute && (
|
||||||
<Info
|
<InfoWithDelta
|
||||||
key={`${member.type}-substitute`}
|
key={`${member.type}-substitute`}
|
||||||
|
decimals={0}
|
||||||
|
unit="%"
|
||||||
indent
|
indent
|
||||||
name={
|
name={
|
||||||
<>
|
<>
|
||||||
<Flex align="center" gap="1">
|
<Flex align="center" gap="1" display="inline-flex">
|
||||||
<AccessibilityIcon />
|
<AccessibilityIcon />
|
||||||
{member.substitute
|
{member.substitute
|
||||||
.map((sub, index) =>
|
.map((sub, index) =>
|
||||||
@@ -495,7 +484,9 @@ export function Characteristics() {
|
|||||||
</Flex>
|
</Flex>
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
/>
|
>
|
||||||
|
{commanderMastery * 1.05 * 100}
|
||||||
|
</InfoWithDelta>
|
||||||
)}
|
)}
|
||||||
</Fragment>
|
</Fragment>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -8,21 +8,26 @@ export function resolveDpm(
|
|||||||
intraClipCoefficient = 1,
|
intraClipCoefficient = 1,
|
||||||
) {
|
) {
|
||||||
const alpha = shell.damage.armor * damageCoefficient;
|
const alpha = shell.damage.armor * damageCoefficient;
|
||||||
|
let dps: number;
|
||||||
|
|
||||||
if (gun.type === 'regular') {
|
if (gun.type === 'regular') {
|
||||||
return (alpha / (reloadCoefficient * gun.reload)) * 60;
|
dps = alpha / (reloadCoefficient * gun.reload);
|
||||||
} else if (gun.type === 'autoLoader') {
|
} else if (gun.type === 'autoLoader') {
|
||||||
return (
|
dps =
|
||||||
((alpha * gun.count) /
|
(alpha * gun.count) /
|
||||||
(gun.reload + (gun.count - 1) * gun.intraClip * intraClipCoefficient)) *
|
(gun.reload * reloadCoefficient +
|
||||||
60
|
(gun.count - 1) * gun.intraClip * intraClipCoefficient);
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
return (
|
if (gun.reload[0] < gun.reload[1] + gun.intraClip) {
|
||||||
((alpha * gun.count) /
|
// first shell's the best
|
||||||
(reloadCoefficient * gun.reload.reduce((a, b) => a + b, 0) +
|
dps = alpha / (gun.reload[0] * reloadCoefficient);
|
||||||
(gun.count - 1) * gun.intraClip * intraClipCoefficient)) *
|
} else {
|
||||||
60
|
dps =
|
||||||
);
|
alpha /
|
||||||
|
(gun.reload.at(-1)! * reloadCoefficient +
|
||||||
|
gun.intraClip * intraClipCoefficient);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return dps * 60;
|
||||||
}
|
}
|
||||||
@@ -75,6 +75,8 @@ export function tankCharacteristics(
|
|||||||
provisionDefinitions: ProvisionDefinitions;
|
provisionDefinitions: ProvisionDefinitions;
|
||||||
},
|
},
|
||||||
) {
|
) {
|
||||||
|
console.log(tank.crew);
|
||||||
|
|
||||||
const presetRows = equipmentDefinitions.presets[tank.equipment];
|
const presetRows = equipmentDefinitions.presets[tank.equipment];
|
||||||
const turretModelDefinition = tankModelDefinition.turrets[turret.id];
|
const turretModelDefinition = tankModelDefinition.turrets[turret.id];
|
||||||
const gunModelDefinition = turretModelDefinition.guns[gun.id];
|
const gunModelDefinition = turretModelDefinition.guns[gun.id];
|
||||||
@@ -138,8 +140,15 @@ export function tankCharacteristics(
|
|||||||
0,
|
0,
|
||||||
) + (hasImprovedVentilation ? 0.08 : 0);
|
) + (hasImprovedVentilation ? 0.08 : 0);
|
||||||
const commanderMastery = crewMastery + provisionCrewBonus;
|
const commanderMastery = crewMastery + provisionCrewBonus;
|
||||||
const crewMemberMastery = commanderMastery * 1.1;
|
const loaderMastery =
|
||||||
|
commanderMastery *
|
||||||
|
(tank.crew.some(({ type }) => type === 'loader') ? 1.1 : 1.05);
|
||||||
|
const gunnerMastery =
|
||||||
|
commanderMastery *
|
||||||
|
(tank.crew.some(({ type }) => type === 'gunner') ? 1.1 : 1.05);
|
||||||
|
const driverMastery =
|
||||||
|
commanderMastery *
|
||||||
|
(tank.crew.some(({ type }) => type === 'driver') ? 1.1 : 1.05);
|
||||||
const intraClipCoefficient = coefficient([hasShellReloadBoost, -0.3]);
|
const intraClipCoefficient = coefficient([hasShellReloadBoost, -0.3]);
|
||||||
const damageCoefficient =
|
const damageCoefficient =
|
||||||
coefficient([hasTungsten, 0.15]) *
|
coefficient([hasTungsten, 0.15]) *
|
||||||
@@ -150,7 +159,7 @@ export function tankCharacteristics(
|
|||||||
);
|
);
|
||||||
const reloadCoefficient =
|
const reloadCoefficient =
|
||||||
(coefficient([hasGunRammer, -0.05]) *
|
(coefficient([hasGunRammer, -0.05]) *
|
||||||
coefficient([true, degressiveStat(crewMemberMastery)])) /
|
coefficient([true, degressiveStat(loaderMastery)])) /
|
||||||
coefficient([hasAdrenaline && gun.type === 'regular', 0.17]);
|
coefficient([hasAdrenaline && gun.type === 'regular', 0.17]);
|
||||||
const penetrationCoefficient = coefficient([
|
const penetrationCoefficient = coefficient([
|
||||||
hasCalibratedShells,
|
hasCalibratedShells,
|
||||||
@@ -173,10 +182,10 @@ export function tankCharacteristics(
|
|||||||
coefficient(
|
coefficient(
|
||||||
[hasEnhancedGunLayingDrive, -0.15],
|
[hasEnhancedGunLayingDrive, -0.15],
|
||||||
[hasReticleCalibration, -0.3],
|
[hasReticleCalibration, -0.3],
|
||||||
) * coefficient([true, degressiveStat(crewMemberMastery)]);
|
) * coefficient([true, degressiveStat(gunnerMastery)]);
|
||||||
const dispersionStillCoefficient =
|
const dispersionStillCoefficient =
|
||||||
coefficient([hasRefinedGun, -0.15], [hasReticleCalibration, -0.3]) *
|
coefficient([hasRefinedGun, -0.15], [hasReticleCalibration, -0.3]) *
|
||||||
coefficient([true, degressiveStat(crewMemberMastery)]);
|
coefficient([true, degressiveStat(gunnerMastery)]);
|
||||||
const dispersionDamagedCoefficient = coefficient([
|
const dispersionDamagedCoefficient = coefficient([
|
||||||
hasVerticalStabilizer,
|
hasVerticalStabilizer,
|
||||||
-0.12,
|
-0.12,
|
||||||
@@ -212,13 +221,13 @@ export function tankCharacteristics(
|
|||||||
);
|
);
|
||||||
const turretTraverseCoefficient =
|
const turretTraverseCoefficient =
|
||||||
coefficient([hasStandardFuel, 0.03], [hasImprovedFuel, 0.1]) *
|
coefficient([hasStandardFuel, 0.03], [hasImprovedFuel, 0.1]) *
|
||||||
coefficient([true, progressiveStat(crewMemberMastery)]);
|
coefficient([true, progressiveStat(gunnerMastery)]);
|
||||||
const hullTraverseCoefficient =
|
const hullTraverseCoefficient =
|
||||||
coefficient(
|
coefficient(
|
||||||
[hasImprovedControl, 0.11],
|
[hasImprovedControl, 0.11],
|
||||||
[hasImprovedEnginePowerBoost, 0.01],
|
[hasImprovedEnginePowerBoost, 0.01],
|
||||||
[true, crewSkills.virtuoso / 100],
|
[true, crewSkills.virtuoso / 100],
|
||||||
) * coefficient([true, progressiveStat(crewMemberMastery)]);
|
) * coefficient([true, progressiveStat(driverMastery)]);
|
||||||
const resistanceHardCoefficient = coefficient([hasImprovedSuspension, -0.2]);
|
const resistanceHardCoefficient = coefficient([hasImprovedSuspension, -0.2]);
|
||||||
const resistanceMediumCoefficient = coefficient([
|
const resistanceMediumCoefficient = coefficient([
|
||||||
hasImprovedSuspension,
|
hasImprovedSuspension,
|
||||||
@@ -305,21 +314,13 @@ export function tankCharacteristics(
|
|||||||
reloadCoefficient,
|
reloadCoefficient,
|
||||||
intraClipCoefficient,
|
intraClipCoefficient,
|
||||||
);
|
);
|
||||||
const dpmMaximum =
|
const mostOptimalShellIndex =
|
||||||
gun.type === 'autoReloader'
|
gun.type === 'autoReloader'
|
||||||
? (
|
? gun.reload[0] + gun.intraClip < gun.reload[1]
|
||||||
gun.count > 2
|
? 1
|
||||||
? gun.reload.at(-1)! < gun.reload.at(-2)!
|
: gun.reload.length
|
||||||
: gun.reload.at(-1)! + gun.intraClip < gun.reload.at(-2)!
|
|
||||||
)
|
|
||||||
? ((damageCoefficient * shell.damage.armor) /
|
|
||||||
(gun.reload.at(-1)! * reloadCoefficient +
|
|
||||||
gun.intraClip * intraClipCoefficient)) *
|
|
||||||
60
|
|
||||||
: ((damageCoefficient * shell.damage.armor) /
|
|
||||||
(gun.reload[0] * reloadCoefficient)) *
|
|
||||||
60
|
|
||||||
: undefined;
|
: undefined;
|
||||||
|
const damage = shell.damage.armor * damageCoefficient;
|
||||||
const dpmEffective =
|
const dpmEffective =
|
||||||
gun.type === 'autoReloader'
|
gun.type === 'autoReloader'
|
||||||
? gun.reload.at(-1)! < gun.reload.at(-2)!
|
? gun.reload.at(-1)! < gun.reload.at(-2)!
|
||||||
@@ -343,13 +344,6 @@ export function tankCharacteristics(
|
|||||||
damageCoefficient * shell.damage.armor * gun.reload.slice(1).length
|
damageCoefficient * shell.damage.armor * gun.reload.slice(1).length
|
||||||
: undefined;
|
: undefined;
|
||||||
const shells = gun.type === 'regular' ? 1 : gun.count;
|
const shells = gun.type === 'regular' ? 1 : gun.count;
|
||||||
console.log(gun.reload);
|
|
||||||
const mostOptimalShellIndex =
|
|
||||||
gun.type === 'autoReloader'
|
|
||||||
? gun.reload[0] + gun.intraClip < gun.reload[1]
|
|
||||||
? 1
|
|
||||||
: gun.reload.length
|
|
||||||
: undefined;
|
|
||||||
const shellReloads =
|
const shellReloads =
|
||||||
gun.type === 'autoReloader'
|
gun.type === 'autoReloader'
|
||||||
? gun.reload.map((reload) => reload * reloadCoefficient)
|
? gun.reload.map((reload) => reload * reloadCoefficient)
|
||||||
@@ -361,7 +355,6 @@ export function tankCharacteristics(
|
|||||||
const caliber = shell.caliber;
|
const caliber = shell.caliber;
|
||||||
const penetration =
|
const penetration =
|
||||||
resolveNearPenetration(shell.penetration) * penetrationCoefficient;
|
resolveNearPenetration(shell.penetration) * penetrationCoefficient;
|
||||||
const damage = shell.damage.armor * damageCoefficient;
|
|
||||||
const clipDamage = gun.type === 'regular' ? undefined : gun.count * damage;
|
const clipDamage = gun.type === 'regular' ? undefined : gun.count * damage;
|
||||||
const moduleDamage = shell.damage.module * damageCoefficient;
|
const moduleDamage = shell.damage.module * damageCoefficient;
|
||||||
const explosionRadius = shell.explosionRadius;
|
const explosionRadius = shell.explosionRadius;
|
||||||
@@ -471,7 +464,6 @@ export function tankCharacteristics(
|
|||||||
shellNormalization,
|
shellNormalization,
|
||||||
shellRicochet,
|
shellRicochet,
|
||||||
dpm,
|
dpm,
|
||||||
dpmMaximum,
|
|
||||||
dpmEffective,
|
dpmEffective,
|
||||||
shells,
|
shells,
|
||||||
mostOptimalShellIndex,
|
mostOptimalShellIndex,
|
||||||
|
|||||||
Reference in new issue
Block a user