From 109c60ca41e6563eeb7994f67a107087f6c538c1 Mon Sep 17 00:00:00 2001 From: Kalle <38327916+Sendouc@users.noreply.github.com> Date: Thu, 8 Sep 2022 18:32:00 +0300 Subject: [PATCH] Analyzer core structure --- app/modules/analyzer/index.ts | 5 + app/modules/analyzer/params.json | 599 +++++++++++++++++++++++++++++ app/modules/analyzer/stats.ts | 61 +++ app/modules/analyzer/types.ts | 117 ++++++ app/modules/analyzer/utils.ts | 23 ++ app/modules/in-game-lists/index.ts | 9 +- app/routes/analyzer.tsx | 7 + scripts/create-analyzer-json.ts | 84 +--- 8 files changed, 827 insertions(+), 78 deletions(-) create mode 100644 app/modules/analyzer/index.ts create mode 100644 app/modules/analyzer/params.json create mode 100644 app/modules/analyzer/stats.ts create mode 100644 app/modules/analyzer/types.ts create mode 100644 app/modules/analyzer/utils.ts create mode 100644 app/routes/analyzer.tsx diff --git a/app/modules/analyzer/index.ts b/app/modules/analyzer/index.ts new file mode 100644 index 000000000..98e8cc5e0 --- /dev/null +++ b/app/modules/analyzer/index.ts @@ -0,0 +1,5 @@ +export type { + DistanceDamage, + MainWeaponParams, + SubWeaponParams, +} from "./types"; diff --git a/app/modules/analyzer/params.json b/app/modules/analyzer/params.json new file mode 100644 index 000000000..8bf44c53b --- /dev/null +++ b/app/modules/analyzer/params.json @@ -0,0 +1,599 @@ +{ + "mainWeapons": { + "0": { + "SpecialPoint": 180, + "subWeaponId": 6, + "specialWeaponId": 11, + "internalName": "Shooter_Short", + "InkConsume": 0.008 + }, + "10": { + "SpecialPoint": 180, + "subWeaponId": 0, + "specialWeaponId": 2, + "internalName": "Shooter_First", + "InkConsume": 0.0043 + }, + "20": { + "SpecialPoint": 200, + "subWeaponId": 2, + "specialWeaponId": 12, + "internalName": "Shooter_Precision", + "InkConsume": 0.008 + }, + "30": { + "SpecialPoint": 200, + "subWeaponId": 5, + "specialWeaponId": 13, + "internalName": "Shooter_Blaze", + "InkConsume": 0.0055 + }, + "40": { + "SpecialPoint": 200, + "subWeaponId": 1, + "specialWeaponId": 1, + "internalName": "Shooter_Normal", + "InkConsume": 0.0092 + }, + "50": { + "SpecialPoint": 200, + "subWeaponId": 4, + "specialWeaponId": 9, + "internalName": "Shooter_Gravity", + "InkConsume": 0.013 + }, + "60": { + "SpecialPoint": 200, + "subWeaponId": 1, + "specialWeaponId": 15, + "internalName": "Shooter_QuickMiddle", + "InkConsume": 0.008 + }, + "70": { + "SpecialPoint": 200, + "subWeaponId": 12, + "specialWeaponId": 12, + "internalName": "Shooter_Expert", + "InkConsume": 0.02 + }, + "80": { + "SpecialPoint": 200, + "subWeaponId": 3, + "specialWeaponId": 8, + "internalName": "Shooter_Heavy", + "InkConsume": 0.025 + }, + "90": { + "SpecialPoint": 200, + "subWeaponId": 12, + "specialWeaponId": 8, + "internalName": "Shooter_Long", + "InkConsume": 0.016 + }, + "200": { + "SpecialPoint": 180, + "subWeaponId": 0, + "specialWeaponId": 3, + "internalName": "Blaster_Short", + "InkConsume": 0.075 + }, + "210": { + "SpecialPoint": 180, + "subWeaponId": 7, + "specialWeaponId": 2, + "internalName": "Blaster_Middle", + "InkConsume": 0.1 + }, + "220": { + "SpecialPoint": 200, + "subWeaponId": 1, + "specialWeaponId": 7, + "internalName": "Blaster_Long", + "InkConsume": 0.11 + }, + "230": { + "SpecialPoint": 180, + "subWeaponId": 0, + "specialWeaponId": 1, + "internalName": "Blaster_LightShort", + "InkConsume": 0.04 + }, + "240": { + "SpecialPoint": 200, + "subWeaponId": 10, + "specialWeaponId": 14, + "internalName": "Blaster_Light", + "InkConsume": 0.07 + }, + "250": { + "SpecialPoint": 180, + "subWeaponId": 11, + "specialWeaponId": 8, + "internalName": "Blaster_LightLong", + "InkConsume": 0.08 + }, + "300": { + "SpecialPoint": 200, + "subWeaponId": 6, + "specialWeaponId": 12, + "internalName": "Shooter_TripleQuick", + "InkConsume": 0.0115 + }, + "310": { + "SpecialPoint": 200, + "subWeaponId": 9, + "specialWeaponId": 15, + "internalName": "Shooter_TripleMiddle", + "InkConsume": 0.0225 + }, + "400": { + "SpecialPoint": 200, + "subWeaponId": 4, + "specialWeaponId": 1, + "internalName": "Shooter_Flash", + "InkConsume": 0.022 + }, + "1000": { + "SpecialPoint": 180, + "subWeaponId": 7, + "specialWeaponId": 3, + "internalName": "Roller_Compact", + "InkConsumeMaxPerFrame_WeaponRollParam": 0.001, + "InkConsumeMinPerFrame_WeaponRollParam": 0.0002, + "InkConsume_WeaponVerticalSwingParam": 0.0396, + "InkConsume_WeaponWideSwingParam": 0.0396 + }, + "1010": { + "SpecialPoint": 180, + "subWeaponId": 6, + "specialWeaponId": 2, + "internalName": "Roller_Normal", + "InkConsumeMaxPerFrame_WeaponRollParam": 0.001, + "InkConsumeMinPerFrame_WeaponRollParam": 0.0002, + "InkConsume_WeaponVerticalSwingParam": 0.085, + "InkConsume_WeaponWideSwingParam": 0.085 + }, + "1020": { + "SpecialPoint": 190, + "subWeaponId": 3, + "specialWeaponId": 15, + "internalName": "Roller_Heavy", + "InkConsumeMaxPerFrame_WeaponRollParam": 0.001, + "InkConsumeMinPerFrame_WeaponRollParam": 0.0002, + "InkConsume_WeaponVerticalSwingParam": 0.18, + "InkConsume_WeaponWideSwingParam": 0.18 + }, + "1030": { + "SpecialPoint": 200, + "subWeaponId": 10, + "specialWeaponId": 4, + "internalName": "Roller_Hunter", + "InkConsumeMaxPerFrame_WeaponRollParam": 0.001, + "InkConsumeMinPerFrame_WeaponRollParam": 0.0002, + "InkConsume_WeaponVerticalSwingParam": 0.12, + "InkConsume_WeaponWideSwingParam": 0.08 + }, + "1100": { + "SpecialPoint": 180, + "subWeaponId": 0, + "specialWeaponId": 9, + "internalName": "Brush_Mini", + "InkConsume_WeaponSwingParam": 0.02, + "InkConsumeMaxPerFrame_WeaponRollParam": 0.00135, + "InkConsumeMinPerFrame_WeaponRollParam": 0.00135 + }, + "1110": { + "SpecialPoint": 200, + "subWeaponId": 1, + "specialWeaponId": 3, + "internalName": "Brush_Normal", + "InkConsume_WeaponSwingParam": 0.032, + "InkConsumeMaxPerFrame_WeaponRollParam": 0.00162, + "InkConsumeMinPerFrame_WeaponRollParam": 0.00162 + }, + "2000": { + "SpecialPoint": 190, + "subWeaponId": 9, + "specialWeaponId": 2, + "internalName": "Charger_Quick", + "InkConsumeFullCharge": 0.105, + "InkConsumeMinCharge": 0.018667 + }, + "2010": { + "SpecialPoint": 200, + "subWeaponId": 0, + "specialWeaponId": 8, + "internalName": "Charger_Normal", + "InkConsumeFullCharge": 0.18, + "InkConsumeMinCharge": 0.0225 + }, + "2020": { + "SpecialPoint": 200, + "subWeaponId": 0, + "specialWeaponId": 8, + "internalName": "Charger_NormalScope", + "InkConsumeFullCharge": 0.18, + "InkConsumeMinCharge": 0.0225 + }, + "2030": { + "SpecialPoint": 200, + "subWeaponId": 10, + "specialWeaponId": 7, + "internalName": "Charger_Long", + "InkConsumeFullCharge": 0.25, + "InkConsumeMinCharge": 0.0225 + }, + "2040": { + "SpecialPoint": 200, + "subWeaponId": 10, + "specialWeaponId": 7, + "internalName": "Charger_LongScope", + "InkConsumeFullCharge": 0.25, + "InkConsumeMinCharge": 0.0225 + }, + "2050": { + "SpecialPoint": 200, + "subWeaponId": 7, + "specialWeaponId": 9, + "internalName": "Charger_Light", + "InkConsumeFullCharge": 0.084, + "InkConsumeMinCharge": 0.0336 + }, + "2060": { + "SpecialPoint": 200, + "subWeaponId": 13, + "specialWeaponId": 4, + "internalName": "Charger_Keeper", + "InkConsumeFullCharge": 0.15, + "InkConsumeMinCharge": 0.02 + }, + "3000": { + "SpecialPoint": 200, + "subWeaponId": 0, + "specialWeaponId": 14, + "internalName": "Slosher_Strong", + "InkConsume": 0.07 + }, + "3010": { + "SpecialPoint": 190, + "subWeaponId": 11, + "specialWeaponId": 10, + "internalName": "Slosher_Diffusion", + "InkConsume": 0.06 + }, + "3020": { + "SpecialPoint": 200, + "subWeaponId": 5, + "specialWeaponId": 6, + "internalName": "Slosher_Launcher", + "InkConsume": 0.084 + }, + "3030": { + "SpecialPoint": 190, + "subWeaponId": 3, + "specialWeaponId": 5, + "internalName": "Slosher_Bathtub", + "InkConsume": 0.08 + }, + "3040": { + "SpecialPoint": 200, + "subWeaponId": 9, + "specialWeaponId": 5, + "internalName": "Slosher_Washtub", + "InkConsume": 0.117 + }, + "4000": { + "SpecialPoint": 180, + "subWeaponId": 2, + "specialWeaponId": 11, + "internalName": "Spinner_Quick", + "InkConsume": 0.1725 + }, + "4010": { + "SpecialPoint": 200, + "subWeaponId": 3, + "specialWeaponId": 7, + "internalName": "Spinner_Standard", + "InkConsume": 0.225 + }, + "4020": { + "SpecialPoint": 190, + "subWeaponId": 7, + "specialWeaponId": 6, + "internalName": "Spinner_Hyper", + "InkConsume": 0.35 + }, + "4030": { + "SpecialPoint": 200, + "subWeaponId": 5, + "specialWeaponId": 10, + "internalName": "Spinner_Downpour", + "InkConsume": 0.25 + }, + "4040": { + "SpecialPoint": 190, + "subWeaponId": 9, + "specialWeaponId": 5, + "internalName": "Spinner_Serein", + "InkConsume": 0.15 + }, + "5000": { + "SpecialPoint": 180, + "subWeaponId": 8, + "specialWeaponId": 15, + "internalName": "Maneuver_Short", + "InkConsume": 0.00663, + "InkConsume_SideStepParam": 0.05 + }, + "5010": { + "SpecialPoint": 200, + "subWeaponId": 1, + "specialWeaponId": 12, + "internalName": "Maneuver_Normal", + "InkConsume": 0.0072, + "InkConsume_SideStepParam": 0.07 + }, + "5020": { + "SpecialPoint": 180, + "subWeaponId": 4, + "specialWeaponId": 6, + "internalName": "Maneuver_Gallon", + "InkConsume": 0.014, + "InkConsume_SideStepParam": 0.08 + }, + "5030": { + "SpecialPoint": 200, + "subWeaponId": 0, + "specialWeaponId": 7, + "internalName": "Maneuver_Dual", + "InkConsume": 0.012, + "InkConsume_SideStepParam": 0.08 + }, + "5040": { + "SpecialPoint": 200, + "subWeaponId": 7, + "specialWeaponId": 13, + "internalName": "Maneuver_Stepper", + "InkConsume": 0.008, + "InkConsume_SideStepParam": 0.03 + }, + "6000": { + "SpecialPoint": 200, + "subWeaponId": 3, + "specialWeaponId": 14, + "internalName": "Shelter_Normal", + "InkConsumeUmbrella_WeaponShelterCanopyParam": 0.3 + }, + "6010": { + "SpecialPoint": 190, + "subWeaponId": 8, + "specialWeaponId": 8, + "internalName": "Shelter_Wide", + "InkConsumeUmbrella_WeaponShelterCanopyParam": 0.3, + "InkConsume_WeaponShelterShotgunParam": 0.11 + }, + "6020": { + "SpecialPoint": 180, + "subWeaponId": 10, + "specialWeaponId": 13, + "internalName": "Shelter_Compact", + "InkConsumeUmbrella_WeaponShelterCanopyParam": 0, + "InkConsume_WeaponShelterShotgunParam": 0.04 + }, + "7010": { + "SpecialPoint": 200, + "subWeaponId": 11, + "specialWeaponId": 9, + "internalName": "Stringer_Normal", + "InkConsumeFullCharge_ChargeParam": 0.085, + "InkConsumeMinCharge_ChargeParam": 0.05 + }, + "8000": { + "SpecialPoint": 200, + "subWeaponId": 2, + "specialWeaponId": 3, + "internalName": "Saber_Normal", + "InkConsume_SwingParam": 0.04, + "InkConsumeFullCharge_ChargeParam": 0.09, + "InkConsumeMinCharge_ChargeParam": 0.035 + } + }, + "subWeapons": { + "0": { + "internalName": "Bomb_Splash", + "InkRecoverStop": 60, + "DistanceDamage": [ + { + "Damage": 1800, + "Distance": 3.6 + }, + { + "Damage": 300, + "Distance": 7 + } + ] + }, + "1": { + "internalName": "Bomb_Suction", + "InkRecoverStop": 60, + "DistanceDamage": [ + { + "Damage": 1800, + "Distance": 4.6 + }, + { + "Damage": 300, + "Distance": 8 + } + ] + }, + "2": { + "internalName": "Bomb_Quick", + "SubInkSaveLv": 0, + "InkConsume": 0.4, + "InkRecoverStop": 50, + "DistanceDamage": [ + { + "Damage": 350, + "Distance": 2.8 + }, + { + "Damage": 250, + "Distance": 4 + } + ] + }, + "3": { + "internalName": "Sprinkler", + "SubInkSaveLv": 3, + "InkConsume": 0.6, + "InkRecoverStop": 60 + }, + "4": { + "internalName": "Shield", + "InkConsume": 0.6, + "InkRecoverStop": 85 + }, + "5": { + "internalName": "Bomb_Fizzy", + "SubInkSaveLv": 1, + "InkConsume": 0.6, + "InkRecoverStop": 70, + "DistanceDamage_BlastParamArray": [ + [ + { + "Damage": 500, + "Distance": 1.6 + }, + { + "Damage": 350, + "Distance": 3.8 + } + ], + [ + { + "Damage": 500, + "Distance": 1.95 + }, + { + "Damage": 350, + "Distance": 4.5 + } + ], + [ + { + "Damage": 500, + "Distance": 2.6 + }, + { + "Damage": 350, + "Distance": 5.45 + } + ] + ] + }, + "6": { + "internalName": "Bomb_Curling", + "InkRecoverStop": 70, + "DistanceDamage_BlastParamMaxCharge": [ + { + "Damage": 1800, + "Distance": 4.6 + }, + { + "Damage": 300, + "Distance": 8 + } + ], + "DistanceDamage_BlastParamMinCharge": [ + { + "Damage": 1800, + "Distance": 1.6 + }, + { + "Damage": 300, + "Distance": 5 + } + ], + "DirectDamage": 200 + }, + "7": { + "internalName": "Bomb_Robot", + "SubInkSaveLv": 1, + "InkConsume": 0.55, + "InkRecoverStop": 85, + "DistanceDamage": [ + { + "Damage": 1800, + "Distance": 2.85 + }, + { + "Damage": 300, + "Distance": 6.5 + } + ] + }, + "8": { + "internalName": "Beacon", + "SubInkSaveLv": 3, + "InkConsume": 0.75, + "InkRecoverStop": 0 + }, + "9": { + "internalName": "PointSensor", + "SubInkSaveLv": 1, + "InkConsume": 0.45, + "InkRecoverStop": 75 + }, + "10": { + "internalName": "Trap", + "SubInkSaveLv": 3, + "InkConsume": 0.6, + "InkRecoverStop": 0, + "DistanceDamage": [ + { + "Damage": 450, + "Distance": 3.6 + }, + { + "Damage": 350, + "Distance": 8 + } + ] + }, + "11": { + "internalName": "PoisonMist", + "SubInkSaveLv": 1, + "InkConsume": 0.6, + "InkRecoverStop": 75 + }, + "12": { + "internalName": "LineMarker", + "SubInkSaveLv": 0, + "InkConsume": 0.4, + "InkRecoverStop": 50, + "DirectDamage": 300 + }, + "13": { + "internalName": "Bomb_Torpedo", + "InkConsume": 0.65, + "InkRecoverStop": 88, + "DistanceDamage_BlastParamChase": [ + { + "Damage": 600, + "Distance": 2.6 + }, + { + "Damage": 350, + "Distance": 6 + } + ], + "DistanceDamage_SplashBlastParam": [ + { + "Damage": 120, + "Distance": 2.6 + } + ] + } + } +} diff --git a/app/modules/analyzer/stats.ts b/app/modules/analyzer/stats.ts new file mode 100644 index 000000000..4c3d15260 --- /dev/null +++ b/app/modules/analyzer/stats.ts @@ -0,0 +1,61 @@ +import type { BuildAbilitiesTupleWithUnknown } from "~/modules/in-game-lists"; +import type { BuildWeapon } from "~/db/types"; +import type { AnalyzedBuild, StatFunctionInput } from "./types"; +import invariant from "tiny-invariant"; +import { buildToAbilityPoints, params } from "./utils"; + +export function buildStats({ + build, + weaponSplId, +}: { + build: BuildAbilitiesTupleWithUnknown; + weaponSplId: BuildWeapon["weaponSplId"]; +}): AnalyzedBuild { + const mainWeaponParams = params().mainWeapons[weaponSplId]; + invariant(mainWeaponParams, `Weapon with splId ${weaponSplId} not found`); + + const subWeaponParams = params().subWeapons[mainWeaponParams.subWeaponId]; + invariant( + subWeaponParams, + `Sub weapon with splId ${mainWeaponParams.subWeaponId} not found` + ); + + const input: StatFunctionInput = { + mainWeaponParams, + subWeaponParams, + abilityPoints: buildToAbilityPoints(build), + }; + + return { + weapon: { + specialWeaponSplId: mainWeaponParams.specialWeaponId, + subWeaponSplId: mainWeaponParams.subWeaponId, + }, + stats: { + shotsPerInkTank: shotsPerInkTank(input), + inkCost: inkCost(input), + specialPoint: specialPoint(input), + subWeaponWhiteInkFrames: subWeaponParams.InkRecoverStop, + }, + }; +} + +function shotsPerInkTank( + args: StatFunctionInput +): AnalyzedBuild["stats"]["shotsPerInkTank"] { + return {}; +} + +function specialPoint( + args: StatFunctionInput +): AnalyzedBuild["stats"]["specialPoint"] { + return { + baseValue: args.mainWeaponParams.SpecialPoint, + modifiedBy: "SCU", + value: args.mainWeaponParams.SpecialPoint, // xxx: + }; +} + +function inkCost(args: StatFunctionInput): AnalyzedBuild["stats"]["inkCost"] { + return {}; +} diff --git a/app/modules/analyzer/types.ts b/app/modules/analyzer/types.ts new file mode 100644 index 000000000..ca5aef723 --- /dev/null +++ b/app/modules/analyzer/types.ts @@ -0,0 +1,117 @@ +import type { Ability } from "~/modules/in-game-lists"; + +export interface MainWeaponParams { + subWeaponId: number; + specialWeaponId: number; + internalName: string; + SpecialPoint: number; + /** How much ink one shot consumes? InkConsume = 0.5 means 2 shots per full tank */ + InkConsume?: number; + /** How much ink one fully charged shot consumes? */ + InkConsumeFullCharge?: number; + /** How much ink one tap shot consumes? */ + InkConsumeMinCharge?: number; + // xxx: morph with another swing one below + /** How much ink one swing of brush consumes? */ + InkConsume_WeaponSwingParam?: number; + /** Lower bound of ink consumed per frame when rolling with roller/brush */ + InkConsumeMaxPerFrame_WeaponRollParam?: number; + /** Upper bound of ink consumed per frame when rolling with roller/brush */ + InkConsumeMinPerFrame_WeaponRollParam?: number; + /** How much ink one vertical swing of roller consumes? */ + InkConsume_WeaponVerticalSwingParam?: number; + /** How much ink one horizontal swing of roller consumes? */ + InkConsume_WeaponWideSwingParam?: number; + /** How much ink one swing of splatana consumes? */ + InkConsume_SwingParam?: number; + /** How much ink brella shield launch consumes? */ + InkConsumeUmbrella_WeaponShelterCanopyParam?: number; + // xxx: splat brella missing this - are we missing extend? + /** How much ink one brella shot consumes? */ + InkConsume_WeaponShelterShotgunParam?: number; + /** How much ink a dualie dodge roll consumes? */ + InkConsume_SideStepParam?: number; + // xxx: some explanations... the below two are for splatana/bow + InkConsumeFullCharge_ChargeParam?: number; + InkConsumeMinCharge_ChargeParam?: number; + //InkConsumeMidCharge_ChargeParam?: number; + // xxx: what are these? + // SpeedInkConsumeMax_WeaponRollParam?: number; + // SpeedInkConsumeMin_WeaponRollParam?: number; +} + +export interface DistanceDamage { + damage: number; + distance: number; +} + +export interface SubWeaponParams { + internalName: string; + SubInkSaveLv: number; + /** How much ink one usage of the sub consumes */ + InkConsume: number; + /** Amount of frames white ink (=no ink recovery during this time) takes */ + InkRecoverStop: number; + /** Damage dealt at different radiuses */ + DistanceDamage?: Array; + /** Damage dealt by explosion at different radiuses (curling bomb charged all the way) */ + DistanceDamage_BlastParamMaxCharge?: Array; + /** Damage dealt by explosion at different radiuses (curling bomb not charged) */ + DistanceDamage_BlastParamMinCharge?: Array; + /** Damage dealt by explosion at different radiuses (fizzy bomb bounces) */ + DistanceDamage_BlastParamArray?: Array; + // xxx: verify torpedo + /** Damage dealt by explosion at different radiuses (torpedo explosion air to ground) */ + DistanceDamage_BlastParamChase?: Array; + /** Damage dealt by explosion at different radiuses (rolling torpedo) */ + DistanceDamage_SplashBlastParam?: Array; + /** Damage dealt by direct hit */ + DirectDamage?: number; +} + +export type ParamsJson = { + mainWeapons: Record; + subWeapons: Record; +}; + +interface Stat { + value: number; + baseValue: number; + modifiedBy: Ability; +} + +export type AbilityPoints = Map; + +export interface StatFunctionInput { + mainWeaponParams: MainWeaponParams; + subWeaponParams: SubWeaponParams; + abilityPoints: AbilityPoints; +} + +type InkConsumeShotType = + | "NORMAL" + | "SWING" + | "VERTICAL_SWING" + | "HORIZONTAL_SWING" + | "TAP_SHOT" + | "FULL_CHARGE"; + +type InkConsumePercentageType = + | "SHIELD_LAUNCH" + | "DUALIE_ROLL" + | "ROLL_MIN" + | "ROLL_MAX"; + +export interface AnalyzedBuild { + weapon: { + subWeaponSplId: number; + specialWeaponSplId: number; + }; + stats: { + specialPoint: Stat; + shotsPerInkTank: Partial>; + /** How much action costs (% of ink tank) */ + inkCost?: Partial>; + subWeaponWhiteInkFrames?: number; + }; +} diff --git a/app/modules/analyzer/utils.ts b/app/modules/analyzer/utils.ts new file mode 100644 index 000000000..dc28e05cf --- /dev/null +++ b/app/modules/analyzer/utils.ts @@ -0,0 +1,23 @@ +import type { BuildAbilitiesTupleWithUnknown } from "../in-game-lists"; +import paramsJson from "./params.json"; +import type { AbilityPoints, ParamsJson } from "./types"; + +export function params(): ParamsJson { + return paramsJson as ParamsJson; +} + +export function buildToAbilityPoints(build: BuildAbilitiesTupleWithUnknown) { + const result: AbilityPoints = new Map(); + + for (const abilityRow of build) { + for (const [i, ability] of abilityRow.entries()) { + if (ability === "UNKNOWN") continue; + + const aps = i === 0 ? 10 : 3; + + result.set(ability, (result.get(ability) ?? 0) + aps); + } + } + + return result; +} diff --git a/app/modules/in-game-lists/index.ts b/app/modules/in-game-lists/index.ts index e152b6648..08f218852 100644 --- a/app/modules/in-game-lists/index.ts +++ b/app/modules/in-game-lists/index.ts @@ -3,4 +3,11 @@ export { modes, modesShort } from "./modes"; export { weaponIds } from "./weapon-ids"; export { headGearIds, clothesGearIds, shoesGearIds } from "./gear-ids"; export { abilitiesShort, abilities } from "./abilities"; -export type { Ability, AbilityType, ModeShort, Stage } from "./types"; +export type { + Ability, + AbilityType, + ModeShort, + Stage, + BuildAbilitiesTuple, + BuildAbilitiesTupleWithUnknown, +} from "./types"; diff --git a/app/routes/analyzer.tsx b/app/routes/analyzer.tsx new file mode 100644 index 000000000..4e7cc7ec6 --- /dev/null +++ b/app/routes/analyzer.tsx @@ -0,0 +1,7 @@ +import { Main } from "~/components/Main"; + +export default function BuildAnalyzerPage() { + if (process.env.NODE_ENV === "production") return
Coming soon :)
; + + return
hellou
; +} diff --git a/scripts/create-analyzer-json.ts b/scripts/create-analyzer-json.ts index 4f4485154..b912dd493 100644 --- a/scripts/create-analyzer-json.ts +++ b/scripts/create-analyzer-json.ts @@ -12,85 +12,17 @@ import specialWeapons from "./dicts/WeaponInfoSpecial.json"; import fs from "node:fs"; import path from "node:path"; import invariant from "tiny-invariant"; +import type { MainWeaponParams, SubWeaponParams } from "~/modules/analyzer"; +import type { ParamsJson } from "~/modules/analyzer/types"; const CURRENT_SEASON = 0; type MainWeapon = typeof weapons[number]; type SubWeapon = typeof subWeapons[number]; -interface MainWeaponParams { - id: number; - subWeaponId: number; - specialWeaponId: number; - internalName: string; - SpecialPoint: number; - /** How much ink one shot consumes? InkConsume = 0.5 means 2 shots per full tank */ - InkConsume?: number; - /** How much ink one fully charged shot consumes? */ - InkConsumeFullCharge?: number; - /** How much ink one tap shot consumes? */ - InkConsumeMinCharge?: number; - /** How much ink one swing of brush consumes? */ - InkConsume_WeaponSwingParam?: number; - /** Lower bound of ink consumed per frame when rolling with roller/brush */ - InkConsumeMaxPerFrame_WeaponRollParam?: number; - /** Upper bound of ink consumed per frame when rolling with roller/brush */ - InkConsumeMinPerFrame_WeaponRollParam?: number; - /** How much ink one vertical swing of roller consumes? */ - InkConsume_WeaponVerticalSwingParam?: number; - /** How much ink one horizontal swing of roller consumes? */ - InkConsume_WeaponWideSwingParam?: number; - /** How much ink one swing of splatana consumes? */ - InkConsume_SwingParam?: number; - /** How much ink brella shield launch consumes? */ - InkConsumeUmbrella_WeaponShelterCanopyParam?: number; - // xxx: splat brella missing this - are we missing extend? - /** How much ink one brella shot consumes? */ - InkConsume_WeaponShelterShotgunParam?: number; - /** How much ink a dualie dodge roll consumes? */ - InkConsume_SideStepParam?: number; - // xxx: some explanations... the below two are for splatana/bow - InkConsumeFullCharge_ChargeParam?: number; - InkConsumeMinCharge_ChargeParam?: number; - //InkConsumeMidCharge_ChargeParam?: number; - // xxx: what are these? - // SpeedInkConsumeMax_WeaponRollParam?: number; - // SpeedInkConsumeMin_WeaponRollParam?: number; -} - -interface DistanceDamage { - damage: number; - distance: number; -} - -interface SubWeaponParams { - id: number; - internalName: string; - SubInkSaveLv: number; - /** How much ink one usage of the sub consumes */ - InkConsume: number; - /** Amount of frames white ink (=no ink recovery during this time) takes */ - InkRecoverStop: number; - /** Damage dealt at different radiuses */ - DistanceDamage?: Array; - /** Damage dealt by explosion at different radiuses (curling bomb charged all the way) */ - DistanceDamage_BlastParamMaxCharge?: Array; - /** Damage dealt by explosion at different radiuses (curling bomb not charged) */ - DistanceDamage_BlastParamMinCharge?: Array; - /** Damage dealt by explosion at different radiuses (fizzy bomb bounces) */ - DistanceDamage_BlastParamArray?: Array; - // xxx: verify torpedo - /** Damage dealt by explosion at different radiuses (torpedo explosion air to ground) */ - DistanceDamage_BlastParamChase?: Array; - /** Damage dealt by explosion at different radiuses (rolling torpedo) */ - DistanceDamage_SplashBlastParam?: Array; - /** Damage dealt by direct hit */ - DirectDamage?: number; -} - function main() { - const mainWeaponsResult: Array = []; - const subWeaponsResult: Array = []; + const mainWeaponsResult: Record = {}; + const subWeaponsResult: Record = {}; for (const weapon of weapons) { if (mainWeaponShouldBeSkipped(weapon)) continue; @@ -98,7 +30,7 @@ function main() { const rawParams = loadWeaponParamsObject(weapon); const params = parametersToMainWeaponResult(weapon, rawParams); - mainWeaponsResult.push(params); + mainWeaponsResult[weapon.Id] = params; } for (const subWeapon of subWeapons) { @@ -107,10 +39,10 @@ function main() { const rawParams = loadWeaponParamsObject(subWeapon); const params = parametersToSubWeaponResult(subWeapon, rawParams); - subWeaponsResult.push(params); + subWeaponsResult[subWeapon.Id] = params; } - const toFile = { + const toFile: ParamsJson = { mainWeapons: mainWeaponsResult, subWeapons: subWeaponsResult, }; @@ -126,7 +58,6 @@ function parametersToMainWeaponResult( params: any ): MainWeaponParams { return { - id: weapon.Id, SpecialPoint: weapon.SpecialPoint, subWeaponId: resolveSubWeaponId(weapon), specialWeaponId: resolveSpecialWeaponId(weapon), @@ -172,7 +103,6 @@ function parametersToSubWeaponResult( params: any ): SubWeaponParams { return { - id: subWeapon.Id, internalName: subWeapon.__RowId, // xxx: not every sub has this, why? e.g. Splash Wall SubInkSaveLv: params["SubWeaponSetting"]?.["SubInkSaveLv"],