From 4b128c59a63dbd8c27e6755d888e664f522f7d44 Mon Sep 17 00:00:00 2001 From: Kalle <38327916+Sendouc@users.noreply.github.com> Date: Sat, 17 Sep 2022 12:58:43 +0300 Subject: [PATCH] BRU effects for analyzer --- app/modules/analyzer/ability-values.json | 8 +- app/modules/analyzer/stats.ts | 77 +++++++++++++++- app/modules/analyzer/types.ts | 10 +++ app/modules/analyzer/utils.ts | 25 +++++- app/modules/analyzer/weapon-params.json | 107 +++++++++++++++++++++++ app/routes/analyzer.tsx | 40 +++++++++ public/locales/en/analyzer.json | 6 ++ scripts/create-analyzer-json.ts | 22 +++++ 8 files changed, 289 insertions(+), 6 deletions(-) diff --git a/app/modules/analyzer/ability-values.json b/app/modules/analyzer/ability-values.json index c97844224..c816bc200 100644 --- a/app/modules/analyzer/ability-values.json +++ b/app/modules/analyzer/ability-values.json @@ -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] } diff --git a/app/modules/analyzer/stats.ts b/app/modules/analyzer/stats.ts index 99499d20e..ab1bb1e70 100644 --- a/app/modules/analyzer/stats.ts +++ b/app/modules/analyzer/stats.ts @@ -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 = {}; + 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; +} diff --git a/app/modules/analyzer/types.ts b/app/modules/analyzer/types.ts index c1d0878c8..9459899bf 100644 --- a/app/modules/analyzer/types.ts +++ b/app/modules/analyzer/types.ts @@ -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>>; 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; diff --git a/app/modules/analyzer/utils.ts b/app/modules/analyzer/utils.ts index dc53ec7d1..052bedd49 100644 --- a/app/modules/analyzer/utils.ts +++ b/app/modules/analyzer/utils.ts @@ -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; +} diff --git a/app/modules/analyzer/weapon-params.json b/app/modules/analyzer/weapon-params.json index f41a2587d..3d483d387 100644 --- a/app/modules/analyzer/weapon-params.json +++ b/app/modules/analyzer/weapon-params.json @@ -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": [ diff --git a/app/routes/analyzer.tsx b/app/routes/analyzer.tsx index ec8a1445f..51ceba2f8 100644 --- a/app/routes/analyzer.tsx +++ b/app/routes/analyzer.tsx @@ -148,6 +148,46 @@ export default function BuildAnalyzerPage() { title={t("analyzer:stat.whiteInk")} suffix={t("analyzer:suffix.seconds")} /> + {analyzed.stats.subVelocity && ( + + )} + {analyzed.stats.subFirstPhaseDuration && ( + + )} + {analyzed.stats.subSecondPhaseDuration && ( + + )} + {analyzed.stats.subMarkingTimeInSeconds && ( + + )} + {analyzed.stats.subMarkingRadius && ( + + )} + {analyzed.stats.subHp && ( + + )} + value && (value.High !== value.Mid || value.Low !== value.High) + ) + ); +} + const WEAPON_TYPES_TO_IGNORE = [ "Mission", "Coop",