applyReactiveArmor

This commit is contained in:
tresabhi committed 2026-10-04 17:22:23 -05:00
1 parent 4e1219486d
commit 870f7d799b
6 files changed
+71 -43

No files matched your search

@@ -1,4 +1,5 @@
import { blitzkitToBlitzShellKind } from "@blitzkit/core";
import { ShellType } from "@blitzkit/protos";
import {
CharacteristicType,
type Characteristic,
@@ -32,7 +33,7 @@ export const characteristics = {
if (environment.equalize) coefficient *= equalizer.damage;
script("TungstenTip", (effect) => {
script("protagonist", "TungstenTip", (effect) => {
coefficient *= (effect.minDamageFactor + effect.maxDamageFactor) / 2;
});
@@ -45,10 +46,15 @@ export const characteristics = {
compute({ shell, script }) {
let coefficient = 1;
script("TungstenTip", (effect) => {
script("protagonist", "TungstenTip", (effect) => {
coefficient *= (effect.minDamageFactor + effect.maxDamageFactor) / 2;
});
script("antagonist", "ShieldKit", (effect) => {
if (shell.type === ShellType.SHELL_TYPE_HE) return;
coefficient *= 1 - effect.shieldCoef;
});
return coefficient * shell.module_damage;
},
},
@@ -58,7 +64,7 @@ export const characteristics = {
compute({ shell, script }) {
let coefficient = 1;
script("CalibratedShells", (effect) => {
script("protagonist", "CalibratedShells", (effect) => {
coefficient *=
1 +
effect.piercingFactors![blitzkitToBlitzShellKind[shell.type]] / 100;
@@ -168,16 +168,13 @@ export function tankCharacteristics(
const intraClipCoefficient = coefficient([hasShellReloadBoost, -0.3]);
const burstShells = gun.burst?.count ?? 1;
const burstInterShell = gun.burst?.interval;
const armorDamageCoefficient =
coefficient([hasTungsten, 0.15]) *
coefficient(
[applyReactiveArmor && shell.type !== ShellType.SHELL_TYPE_HE, -0.27],
[applyDynamicArmor, -0.1],
[
applySpallLiner && shell.type === ShellType.SHELL_TYPE_HE,
SPALL_LINER_HE_DAMAGE_DELTA,
],
);
const armorDamageCoefficient = coefficient(
[applyDynamicArmor, -0.1],
[
applySpallLiner && shell.type === ShellType.SHELL_TYPE_HE,
SPALL_LINER_HE_DAMAGE_DELTA,
],
);
const assaultDamageCoefficient =
gun.assault_ranges && gun.assault_ranges.types.includes(shell.type)
? (gun.assault_ranges.ranges.find(
@@ -9,51 +9,65 @@ import type {
CharacteristicName,
ComputedCharacteristics,
} from "../types/characteristics";
import type { DuelSide } from "./useEquipment";
import { duelSides, type DuelSide } from "./useEquipment";
const tanks = await api.tanks();
const scripts = await api.scripts();
const equipment = await api.equipment();
export function useCharacteristics(side: DuelSide) {
const state = Tankopedia.use((state) => state[side]);
export function useCharacteristics() {
const protagonist = Tankopedia.use((state) => state.protagonist);
const antagonist = Tankopedia.use((state) => state.antagonist);
const environment = Tankopedia.use((state) => state.environment);
return computeCharacteristics(state, environment);
return computeCharacteristics({ protagonist, antagonist }, environment);
}
export function computeCharacteristics(
state: TankState,
states: Record<DuelSide, TankState>,
environment: TankEnvironment,
) {
const computed: ComputedCharacteristics = new Map();
const tank = tanks.tanks[state.tank];
const engine = tank.engines.find((engine) => engine.id === state.engine)!;
const track = tank.tracks.find((track) => track.id === state.track)!;
const turret = tank.turrets.find((turret) => turret.id === state.turret)!;
const gun = turret.guns.find((gun) => gun.id === state.gun)!;
const shell = gun.shells.find((shell) => shell.id === state.shell)!;
const tank = tanks.tanks[states.protagonist.tank];
const engine = tank.engines.find(
(engine) => engine.id === states.protagonist.engine,
)!;
const track = tank.tracks.find(
(track) => track.id === states.protagonist.track,
)!;
const turret = tank.turrets.find(
(turret) => turret.id === states.protagonist.turret,
)!;
const gun = turret.guns.find((gun) => gun.id === states.protagonist.gun)!;
const shell = gun.shells.find(
(shell) => shell.id === states.protagonist.shell,
)!;
const equipmentPreset = equipment.presets[tank.equipment_preset];
const scriptsMap = new Map<string, BlitzEffectScript>();
const scriptsMap: Record<DuelSide, Map<string, BlitzEffectScript>> = {
protagonist: new Map(),
antagonist: new Map(),
};
for (const id of state.consumables) {
if (!(id in scripts.consumables)) continue;
for (const side of duelSides) {
for (const id of states[side].consumables) {
if (!(id in scripts.consumables)) continue;
const script = scripts.consumables[id];
scriptsMap.set(script["#text"], script);
}
const script = scripts.consumables[id];
scriptsMap.protagonist.set(script["#text"], script);
}
for (const index in state.equipment) {
const choice = state.equipment[index];
const id = equipmentPreset.slots[index].options[choice];
for (const index in states[side].equipment) {
const choice = states[side].equipment[index];
const id = equipmentPreset.slots[index].options[choice];
if (!(id in scripts.equipment)) continue;
if (!(id in scripts.equipment)) continue;
const script = scripts.equipment[id];
scriptsMap.set(script["#text"], script);
const script = scripts.equipment[id];
scriptsMap.protagonist.set(script["#text"], script);
}
}
function characteristic(name: CharacteristicName) {
@@ -66,13 +80,17 @@ export function computeCharacteristics(
console.log(scriptsMap);
function script(name: string, callback: (effect: BlitzEffectScript) => void) {
if (!scriptsMap.has(name)) return;
callback(scriptsMap.get(name)!);
function script(
side: DuelSide,
name: string,
callback: (effect: BlitzEffectScript) => void,
) {
if (!scriptsMap[side].has(name)) return;
callback(scriptsMap[side].get(name)!);
}
const context = {
state,
state: states.protagonist,
environment,
equalizer: tank.equalizer ?? defaultEqualizer,
+3 -1
View File
@@ -5,7 +5,9 @@ import { Tankopedia } from "../stores/tankopedia";
const equipment = await api.equipment();
const tanks = await api.tanks();
export type DuelSide = "protagonist" | "antagonist";
export const duelSides = ["protagonist", "antagonist"] as const;
export type DuelSide = (typeof duelSides)[number];
export function useEquipment(side: DuelSide, id: number) {
const member = Tankopedia.use((state) => state[side]);
@@ -27,7 +27,7 @@ export const Page = withErrorWrapper(
const protagonist = Tankopedia.use((state) => state.protagonist);
const equalize = Tankopedia.use((state) => state.environment.equalize);
const characteristics = useCharacteristics("protagonist");
const characteristics = useCharacteristics();
const thicknessRange = useMemo(() => {
const entries = Object.values(tanks.tanks);
@@ -11,6 +11,7 @@ import type {
} from "@blitzkit/protos";
import type { ReactNode } from "react";
import { characteristics } from "../config/characteristics";
import type { DuelSide } from "../hooks/useEquipment";
import type { TankEnvironment } from "../stores/tankopedia";
import type { TankState } from "../tankopedia/tankState";
@@ -44,7 +45,11 @@ export interface CharacteristicContext {
name: CharacteristicName,
): ReturnType<Characteristic["compute"]>;
script(name: string, effect: (effect: BlitzEffectScript) => void): void;
script(
side: DuelSide,
name: string,
effect: (effect: BlitzEffectScript) => void,
): void;
}
export enum CharacteristicType {