BRU effects for analyzer

This commit is contained in:
Kalle
2022-09-17 12:58:43 +03:00
parent e87fd714e2
commit 4b128c59a6
8 changed files with 289 additions and 6 deletions

View File

@@ -38,5 +38,11 @@
"SuperJump_ChargeFrm": [20.0, 35.0, 80.0],
"SuperJump_MoveFrm": [96.6, 132.3, 138.0],
"WallJumpChargeFrm": [0.0, 0.0, 0.0],
"ReduceJumpSwerveRate": [1.0, 0.75, 0.0]
"ReduceJumpSwerveRate": [1.0, 0.75, 0.0],
"SpawnSpeedZSpecUp": [0.0, 0.0, 0.0],
"PeriodFirst": [0.0, 0.0, 0.0],
"PeriodSecond": [0.0, 0.0, 0.0],
"MarkingFrameSubSpec": [0.0, 0.0, 0.0],
"SensorRadius": [0.0, 0.0, 0.0],
"MaxHP": [0.0, 0.0, 0.0]
}

View File

@@ -11,9 +11,15 @@ import type {
import { DAMAGE_TYPE } from "./types";
import { INK_CONSUME_TYPES } from "./types";
import invariant from "tiny-invariant";
import { abilityPointsToEffects, apFromMap, weaponParams } from "./utils";
import {
abilityPointsToEffects,
apFromMap,
hasEffect,
weaponParams,
} from "./utils";
import { assertUnreachable } from "~/utils/types";
import { semiRandomId } from "~/utils/strings";
import { roundToTwoDecimalPlaces } from "~/utils/number";
export function buildStats({
abilityPoints,
@@ -74,6 +80,7 @@ export function buildStats({
quickRespawnTime: quickRespawnTime(input),
superJumpTimeGroundFrames: superJumpTimeGroundFrames(input),
superJumpTimeTotal: superJumpTimeTotal(input),
...subStats(input),
},
};
}
@@ -559,3 +566,71 @@ function framesBeforeTakingDamageInEnemyInk(
modifiedBy: FRAMES_BEFORE_TAKING_DAMAGE_IN_ENEMY_INK_ABILITY,
};
}
const SUB_WEAPON_STATS = [
{
analyzedBuildKey: "subVelocity",
abilityValuesKey: "SpawnSpeedZSpecUp",
type: "NO_CHANGE",
},
{
analyzedBuildKey: "subFirstPhaseDuration",
abilityValuesKey: "PeriodFirst",
type: "TIME",
},
{
analyzedBuildKey: "subSecondPhaseDuration",
abilityValuesKey: "PeriodSecond",
type: "TIME",
},
{
analyzedBuildKey: "subMarkingTimeInSeconds",
abilityValuesKey: "MarkingFrameSubSpec",
type: "TIME",
},
{
analyzedBuildKey: "subMarkingRadius",
abilityValuesKey: "SensorRadius",
type: "NO_CHANGE",
},
{ analyzedBuildKey: "subHp", abilityValuesKey: "MaxHP", type: "HP" },
] as const;
function subStats(args: StatFunctionInput) {
const result: Partial<AnalyzedBuild["stats"]> = {};
const SUB_STATS_KEY = "BRU";
for (const { analyzedBuildKey, abilityValuesKey, type } of SUB_WEAPON_STATS) {
if (!hasEffect({ key: abilityValuesKey, weapon: args.subWeaponParams })) {
continue;
}
const { baseEffect, effect } = abilityPointsToEffects({
abilityPoints: apFromMap({
abilityPoints: args.abilityPoints,
ability: SUB_STATS_KEY,
}),
key: abilityValuesKey,
weapon: args.subWeaponParams,
});
const toValue = (effect: number) => {
switch (type) {
case "NO_CHANGE":
return roundToTwoDecimalPlaces(effect);
case "HP":
return roundToTwoDecimalPlaces(effect / 10);
case "TIME":
return framesToSeconds(effect);
default:
assertUnreachable(type);
}
};
result[analyzedBuildKey] = {
baseValue: toValue(baseEffect),
modifiedBy: SUB_STATS_KEY,
value: toValue(effect),
};
}
return result;
}

View File

@@ -5,6 +5,7 @@ import type {
SubWeaponId,
} from "~/modules/in-game-lists";
import type { SPECIAL_EFFECTS } from "./specialEffects";
import type abilityValues from "./ability-values.json";
export interface MainWeaponParams {
subWeaponId: SubWeaponId;
@@ -78,6 +79,7 @@ export interface DistanceDamage {
}
export interface SubWeaponParams {
overwrites?: Record<string, Partial<Record<"High" | "Mid" | "Low", number>>>;
SubInkSaveLv: 0 | 1 | 2 | 3;
/** How much ink one usage of the sub consumes */
InkConsume: number;
@@ -191,7 +193,15 @@ export interface AnalyzedBuild {
quickRespawnTime: Stat;
superJumpTimeGroundFrames: Stat;
superJumpTimeTotal: Stat;
subVelocity?: Stat;
subFirstPhaseDuration?: Stat;
subSecondPhaseDuration?: Stat;
subMarkingTimeInSeconds?: Stat;
subMarkingRadius?: Stat;
subHp?: Stat;
};
}
export type SpecialEffectType = typeof SPECIAL_EFFECTS[number]["type"];
export type AbilityValuesKeys = keyof typeof abilityValues;

View File

@@ -2,7 +2,12 @@ import type { Ability, BuildAbilitiesTupleWithUnknown } from "../in-game-lists";
import { abilities } from "../in-game-lists";
import weaponParamsJson from "./weapon-params.json";
import abilityValuesJson from "./ability-values.json";
import type { AbilityPoints, MainWeaponParams, ParamsJson } from "./types";
import type {
AbilityPoints,
MainWeaponParams,
ParamsJson,
SubWeaponParams,
} from "./types";
import invariant from "tiny-invariant";
import type { AbilityWithUnknown } from "../in-game-lists/types";
@@ -58,7 +63,7 @@ function abilityValues({
weapon,
}: {
key: keyof typeof abilityValuesJson;
weapon: MainWeaponParams;
weapon: MainWeaponParams | SubWeaponParams;
}): [number, number, number] {
const overwrites = weapon.overwrites?.[key];
@@ -106,7 +111,7 @@ function abilityPointsToEffect({
}: {
key: keyof typeof abilityValuesJson;
abilityPoints: number;
weapon: MainWeaponParams;
weapon: MainWeaponParams | SubWeaponParams;
}) {
const [high, mid, low] = abilityValues({ key, weapon });
@@ -126,10 +131,22 @@ export function abilityPointsToEffects({
}: {
key: keyof typeof abilityValuesJson;
abilityPoints: number;
weapon: MainWeaponParams;
weapon: MainWeaponParams | SubWeaponParams;
}) {
return {
baseEffect: abilityPointsToEffect({ key, abilityPoints: 0, weapon }),
effect: abilityPointsToEffect({ key, abilityPoints, weapon }),
};
}
export function hasEffect({
key,
weapon,
}: {
key: keyof typeof abilityValuesJson;
weapon: MainWeaponParams | SubWeaponParams;
}) {
const [high, mid, low] = abilityValues({ key, weapon });
return high !== mid || mid !== low;
}

View File

@@ -664,6 +664,13 @@
},
"subWeapons": {
"0": {
"overwrites": {
"SpawnSpeedZSpecUp": {
"High": 1.68,
"Low": 1.12,
"Mid": 1.4
}
},
"InkRecoverStop": 60,
"DistanceDamage": [
{
@@ -677,6 +684,13 @@
]
},
"1": {
"overwrites": {
"SpawnSpeedZSpecUp": {
"High": 1.68,
"Low": 1.12,
"Mid": 1.4
}
},
"InkRecoverStop": 60,
"DistanceDamage": [
{
@@ -690,6 +704,13 @@
]
},
"2": {
"overwrites": {
"SpawnSpeedZSpecUp": {
"High": 1.68,
"Low": 1.12,
"Mid": 1.4
}
},
"SubInkSaveLv": 0,
"InkConsume": 0.4,
"InkRecoverStop": 50,
@@ -705,15 +726,41 @@
]
},
"3": {
"overwrites": {
"PeriodFirst": {
"High": 600,
"Low": 300,
"Mid": 450
},
"PeriodSecond": {
"High": 1020,
"Low": 900,
"Mid": 960
}
},
"SubInkSaveLv": 3,
"InkConsume": 0.6,
"InkRecoverStop": 60
},
"4": {
"overwrites": {
"MaxHP": {
"High": 15000,
"Low": 8000,
"Mid": 11500
}
},
"InkConsume": 0.6,
"InkRecoverStop": 85
},
"5": {
"overwrites": {
"SpawnSpeedZSpecUp": {
"High": 1.84,
"Low": 1.36,
"Mid": 1.6
}
},
"SubInkSaveLv": 1,
"InkConsume": 0.6,
"InkRecoverStop": 70,
@@ -751,6 +798,13 @@
]
},
"6": {
"overwrites": {
"SpawnSpeedZSpecUp": {
"High": 0.52,
"Low": 0.4,
"Mid": 0.46
}
},
"InkRecoverStop": 70,
"DistanceDamage_BlastParamMaxCharge": [
{
@@ -775,6 +829,13 @@
"DirectDamage": 200
},
"7": {
"overwrites": {
"SpawnSpeedZSpecUp": {
"High": 1.68,
"Low": 1.12,
"Mid": 1.4
}
},
"SubInkSaveLv": 1,
"InkConsume": 0.55,
"InkRecoverStop": 85,
@@ -790,16 +851,36 @@
]
},
"8": {
"overwrites": {},
"SubInkSaveLv": 3,
"InkConsume": 0.75,
"InkRecoverStop": 0
},
"9": {
"overwrites": {
"SpawnSpeedZSpecUp": {
"High": 1.87,
"Low": 1.38,
"Mid": 1.64
},
"MarkingFrameSubSpec": {
"High": 960,
"Low": 480,
"Mid": 720
}
},
"SubInkSaveLv": 1,
"InkConsume": 0.45,
"InkRecoverStop": 75
},
"10": {
"overwrites": {
"SensorRadius": {
"High": 4,
"Low": 3,
"Mid": 3.5
}
},
"SubInkSaveLv": 3,
"InkConsume": 0.6,
"InkRecoverStop": 0,
@@ -815,17 +896,43 @@
]
},
"11": {
"overwrites": {
"SpawnSpeedZSpecUp": {
"High": 1.68,
"Low": 1.12,
"Mid": 1.4
}
},
"SubInkSaveLv": 1,
"InkConsume": 0.6,
"InkRecoverStop": 75
},
"12": {
"overwrites": {
"SpawnSpeedZSpecUp": {
"High": 5.4,
"Low": 5,
"Mid": 5.2
},
"MarkingFrameSubSpec": {
"High": 600,
"Low": 300,
"Mid": 450
}
},
"SubInkSaveLv": 0,
"InkConsume": 0.4,
"InkRecoverStop": 50,
"DirectDamage": 300
},
"13": {
"overwrites": {
"SpawnSpeedZSpecUp": {
"High": 1.84,
"Low": 1.36,
"Mid": 1.6
}
},
"InkConsume": 0.65,
"InkRecoverStop": 88,
"DistanceDamage_BlastParamChase": [

View File

@@ -148,6 +148,46 @@ export default function BuildAnalyzerPage() {
title={t("analyzer:stat.whiteInk")}
suffix={t("analyzer:suffix.seconds")}
/>
{analyzed.stats.subVelocity && (
<StatCard
stat={analyzed.stats.subVelocity}
title={t("analyzer:stat.sub.velocity")}
/>
)}
{analyzed.stats.subFirstPhaseDuration && (
<StatCard
stat={analyzed.stats.subFirstPhaseDuration}
title={t("analyzer:stat.sub.firstPhaseDuration")}
suffix={t("analyzer:suffix.seconds")}
/>
)}
{analyzed.stats.subSecondPhaseDuration && (
<StatCard
stat={analyzed.stats.subSecondPhaseDuration}
title={t("analyzer:stat.sub.secondPhaseDuration")}
suffix={t("analyzer:suffix.seconds")}
/>
)}
{analyzed.stats.subMarkingTimeInSeconds && (
<StatCard
stat={analyzed.stats.subMarkingTimeInSeconds}
title={t("analyzer:stat.sub.markingTimeInSeconds")}
suffix={t("analyzer:suffix.seconds")}
/>
)}
{analyzed.stats.subMarkingRadius && (
<StatCard
stat={analyzed.stats.subMarkingRadius}
title={t("analyzer:stat.sub.markingRadius")}
/>
)}
{analyzed.stats.subHp && (
<StatCard
stat={analyzed.stats.subHp}
title={t("analyzer:stat.sub.hp")}
suffix={t("analyzer:suffix.hp")}
/>
)}
</StatCategory>
<StatCategory title={t("analyzer:stat.category.special")}>
<StatCard

View File

@@ -36,6 +36,12 @@
"stat.consumption.SPLATLING_CHARGE": "Full charges",
"stat.consumption.SHIELD_LAUNCH": "Shield launches",
"stat.consumption.DUALIE_ROLL": "Dodge Rolls",
"stat.sub.velocity": "Velocity (decides range)",
"stat.sub.firstPhaseDuration": "Full power phase duration",
"stat.sub.secondPhaseDuration": "Mid phase duration",
"stat.sub.markingTimeInSeconds": "Marking duration",
"stat.sub.markingRadius": "Marking radius",
"stat.sub.hp": "Durability",
"damage.header.type": "Type",
"damage.header.damage": "Damage",
"damage.header.distance": "Distance",

View File

@@ -218,6 +218,7 @@ function parametersToSubWeaponResult(params: any): SubWeaponParams {
// );
return {
overwrites: resolveSubWeaponOverwrites(params),
// xxx: not every sub has this, why? e.g. Splash Wall
SubInkSaveLv,
InkConsume: params["WeaponParam"]["InkConsume"],
@@ -337,6 +338,27 @@ function resolveOverwritesWithArbitraryKeys(
}
}
function resolveSubWeaponOverwrites(params: any) {
const result: SubWeaponParams["overwrites"] = {
SpawnSpeedZSpecUp: params["MoveParam"]?.["SpawnSpeedZSpecUp"],
PeriodFirst: params["MoveParam"]?.["PeriodFirst"],
PeriodSecond: params["MoveParam"]?.["PeriodSecond"],
MarkingFrameSubSpec:
params["MoveParam"]?.["MarkingFrameSubSpec"] ??
params["MoveParam"]?.["MarkingFrame"],
SensorRadius: params["MoveParam"]?.["SensorRadius"],
MaxHP: params["MoveParam"]?.["MaxHP"],
// xxx: missing Squid Beakon AP up
};
return Object.fromEntries(
Object.entries(result).filter(
([_key, value]) =>
value && (value.High !== value.Mid || value.Low !== value.High)
)
);
}
const WEAPON_TYPES_TO_IGNORE = [
"Mission",
"Coop",