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