mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-22 11:17:05 +02:00
feat: more accurate HE
This commit is contained in:
1 parent
f5578ee788
commit
199e156e53
5 files changed
+61
-20
No files matched your search
@@ -53,8 +53,8 @@ void main() {
|
||||
float spacedArmorThickness = spacedArmorBufferFragment.r * penetration;
|
||||
remainingPenetration -= spacedArmorThickness;
|
||||
|
||||
if (isExplosive && remainingPenetration > 0.0) {
|
||||
// there is a 50% penetration loss per meter for HE based shells
|
||||
if (isExplosive && !canSplash && remainingPenetration > 0.0) {
|
||||
// there is a 50% penetration loss per meter for HEAT shells
|
||||
remainingPenetration -= 0.5 * remainingPenetration * distanceFromSpacedArmor;
|
||||
}
|
||||
}
|
||||
@@ -68,7 +68,7 @@ void main() {
|
||||
// only allow splashing if the damage equation deals more than 0 damage
|
||||
float nominalArmorThickness = finalThickness - remainingPenetration;
|
||||
float finalDamage = 0.5 * damage * (1.0 - distanceFromSpacedArmor / explosionRadius) - 1.1 * nominalArmorThickness;
|
||||
splashChance = finalDamage > 0.0 ? 1.0 : 0.0;
|
||||
splashChance = finalDamage > 0.0 ? 1.0 : 0.0; // TODO: add randomization here?
|
||||
} else {
|
||||
splashChance = 0.0;
|
||||
}
|
||||
|
||||
@@ -4,13 +4,17 @@ import { Euler, Quaternion, Vector3 } from 'three';
|
||||
import { radToDeg } from 'three/src/math/MathUtils';
|
||||
import { J_HAT } from '../../../constants/axis';
|
||||
import { isExplosive } from '../../../core/blitz/isExplosive';
|
||||
import { NaNFallback } from '../../../core/math/NaNFallback';
|
||||
import { AngledPenetration } from '../../../icons/AngledPenetration';
|
||||
import { Block } from '../../../icons/Block';
|
||||
import { NominalPenetration } from '../../../icons/NominalPenetration';
|
||||
import { Ricochet } from '../../../icons/Ricochet';
|
||||
import { useDuel } from '../../../stores/duel';
|
||||
import {
|
||||
ShotLayer,
|
||||
ShotLayerBase,
|
||||
ShotLayerGap,
|
||||
ShotLayerNonExternal,
|
||||
useTankopediaTemporary,
|
||||
} from '../../../stores/tankopedia';
|
||||
import { ArmorType } from './SpacedArmorScene';
|
||||
@@ -79,10 +83,10 @@ export function ShotDisplay() {
|
||||
style={{
|
||||
backgroundColor:
|
||||
trueStatus === 'penetration'
|
||||
? '#00ff0080'
|
||||
? '#00ff00c0'
|
||||
: trueStatus === 'blocked'
|
||||
? '#ff000080'
|
||||
: '#ffff0080',
|
||||
? '#ff0000c0'
|
||||
: '#ffff00c0',
|
||||
border: 'none',
|
||||
}}
|
||||
>
|
||||
@@ -93,9 +97,11 @@ export function ShotDisplay() {
|
||||
width: '100%',
|
||||
display: 'block',
|
||||
textAlign: 'center',
|
||||
color:
|
||||
trueStatus === 'ricochet' ? 'black' : undefined,
|
||||
}}
|
||||
>
|
||||
{layer.index + 1}
|
||||
<b>{layer.index + 1}</b>
|
||||
</Text>
|
||||
)}
|
||||
</Inset>
|
||||
@@ -155,25 +161,54 @@ export function ShotDisplay() {
|
||||
|
||||
{shot &&
|
||||
(() => {
|
||||
const firstLayer = shot.layers[0] as Exclude<ShotLayer, ShotLayerGap>;
|
||||
const lastLayer = shot.layers.at(-1)!;
|
||||
const lastStatus = lastLayer.status;
|
||||
const midPointLayer = (shot.layers.findLast(
|
||||
(layer) => layer.type !== null && layer.status === 'ricochet',
|
||||
) ??
|
||||
shot.layers.findLast(
|
||||
(layer) => layer.type !== null,
|
||||
)) as ShotLayerBase;
|
||||
const distanceFromSpacedArmor = firstLayer.point.distanceTo(
|
||||
shot.point,
|
||||
);
|
||||
|
||||
console.log(distanceFromSpacedArmor);
|
||||
|
||||
return (
|
||||
<Html
|
||||
position={shot.point}
|
||||
position={midPointLayer.point}
|
||||
style={{
|
||||
transform: 'translateY(-50%)',
|
||||
marginLeft: 16,
|
||||
marginLeft: 32,
|
||||
pointerEvents: 'none',
|
||||
}}
|
||||
>
|
||||
<Card style={{ width: 256 + 32 }}>
|
||||
<Flex direction="column">
|
||||
<Text>
|
||||
{lastStatus[0].toUpperCase()}
|
||||
{lastStatus.slice(1)}
|
||||
{lastStatus === 'penetration' &&
|
||||
`: ${shell.damage.module}hp`}
|
||||
{lastLayer.status[0].toUpperCase()}
|
||||
{lastLayer.status.slice(1)}
|
||||
{lastLayer.status === 'penetration' &&
|
||||
`: ${Math.round(shell.damage.armor)}hp`}
|
||||
{lastLayer.status === 'blocked' &&
|
||||
shell.type === 'he' &&
|
||||
`: ${NaNFallback(
|
||||
Math.max(
|
||||
0,
|
||||
Math.round(
|
||||
0.5 *
|
||||
shell.damage.armor *
|
||||
(1 -
|
||||
distanceFromSpacedArmor /
|
||||
shell.explosionRadius!) -
|
||||
1.1 *
|
||||
(midPointLayer as ShotLayerNonExternal)
|
||||
.thicknessAngled,
|
||||
),
|
||||
),
|
||||
0,
|
||||
)}hp`}
|
||||
</Text>
|
||||
|
||||
{shot.layers.map((layer) => {
|
||||
@@ -223,6 +258,7 @@ export function ShotDisplay() {
|
||||
|
||||
{layer.type === null && (
|
||||
<Text size="2">
|
||||
{/* why is it x50? i can't pretend to understand this shit */}
|
||||
{Math.round(layer.distance * 1000)}mm (-
|
||||
{Math.round(Math.min(100, layer.distance * 50))}%
|
||||
penetration)
|
||||
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
Vector3,
|
||||
} from 'three';
|
||||
import { degToRad } from 'three/src/math/MathUtils';
|
||||
import { canSplash } from '../../../../core/blitz/canSplash';
|
||||
import { isExplosive } from '../../../../core/blitz/isExplosive';
|
||||
import { resolveNearPenetration } from '../../../../core/blitz/resolveNearPenetration';
|
||||
import { hasEquipment } from '../../../../core/blitzkrieg/hasEquipment';
|
||||
@@ -93,6 +94,7 @@ export function SpacedArmorSceneComponent({
|
||||
const thicknessCoefficient = hasEnhancedArmor ? 1.04 : 1;
|
||||
const shell = useDuel.getState().antagonist!.shell;
|
||||
const explosive = isExplosive(shell.type);
|
||||
const splashing = canSplash(shell.type);
|
||||
const penetration =
|
||||
resolveNearPenetration(shell.penetration) *
|
||||
(hasCalibratedShells
|
||||
@@ -171,17 +173,17 @@ export function SpacedArmorSceneComponent({
|
||||
const distance = (
|
||||
shot.layers.at(-1) as ShotLayerBase
|
||||
).point.distanceTo(intersections[0].point);
|
||||
if (explosive)
|
||||
if (explosive && !splashing)
|
||||
remainingPenetration -= 0.5 * remainingPenetration * distance;
|
||||
const wasted = remainingPenetration < 0;
|
||||
const blocked = remainingPenetration < 0;
|
||||
|
||||
shot.layers.push({
|
||||
type: null,
|
||||
status: wasted ? 'blocked' : 'penetration',
|
||||
status: blocked ? 'blocked' : 'penetration',
|
||||
distance,
|
||||
});
|
||||
|
||||
if (wasted) return;
|
||||
if (blocked) return;
|
||||
}
|
||||
|
||||
for (const intersection of intersections) {
|
||||
@@ -197,7 +199,7 @@ export function SpacedArmorSceneComponent({
|
||||
const previousIntersection = intersections[layerIndex - 1];
|
||||
const distance =
|
||||
intersection.distance - previousIntersection.distance;
|
||||
if (explosive)
|
||||
if (explosive && !splashing)
|
||||
remainingPenetration -=
|
||||
0.5 * remainingPenetration * distance;
|
||||
const wasted = remainingPenetration < 0;
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
export function NaNFallback(value: number, fallback: number) {
|
||||
return isNaN(value) ? fallback : value;
|
||||
}
|
||||
@@ -57,7 +57,7 @@ interface ShotLayerExternal extends ShotLayerBase {
|
||||
type: ArmorType.External;
|
||||
}
|
||||
|
||||
interface ShotLayerNonExternal extends ShotLayerBase {
|
||||
export interface ShotLayerNonExternal extends ShotLayerBase {
|
||||
type: Exclude<ArmorType, ArmorType.External>;
|
||||
angle: number;
|
||||
thicknessAngled: number;
|
||||
|
||||
Reference in new issue
Block a user