From cefb55d19f1fa55c3c3ab2b0ca1eb7d588929d50 Mon Sep 17 00:00:00 2001 From: Kalle <38327916+Sendouc@users.noreply.github.com> Date: Fri, 16 Sep 2022 17:59:06 +0300 Subject: [PATCH] Effect and LDE intensity in Search Params --- app/modules/analyzer/specialEffects.ts | 2 +- app/modules/analyzer/types.ts | 3 + app/modules/analyzer/useAnalyzeBuild.ts | 86 ++++++++++++++++++++++--- app/modules/in-game-lists/index.ts | 1 + app/modules/in-game-lists/utils.ts | 6 ++ app/routes/analyzer.tsx | 13 ++-- 6 files changed, 96 insertions(+), 15 deletions(-) create mode 100644 app/modules/in-game-lists/utils.ts diff --git a/app/modules/analyzer/specialEffects.ts b/app/modules/analyzer/specialEffects.ts index cba320058..94b555003 100644 --- a/app/modules/analyzer/specialEffects.ts +++ b/app/modules/analyzer/specialEffects.ts @@ -2,7 +2,7 @@ import type { AbilityPoints } from "./types"; const MAX_AP = 57; -const SPECIAL_EFFECTS = [ +export const SPECIAL_EFFECTS = [ { type: "OG", values: [ diff --git a/app/modules/analyzer/types.ts b/app/modules/analyzer/types.ts index a61c02123..c1d0878c8 100644 --- a/app/modules/analyzer/types.ts +++ b/app/modules/analyzer/types.ts @@ -4,6 +4,7 @@ import type { SpecialWeaponId, SubWeaponId, } from "~/modules/in-game-lists"; +import type { SPECIAL_EFFECTS } from "./specialEffects"; export interface MainWeaponParams { subWeaponId: SubWeaponId; @@ -192,3 +193,5 @@ export interface AnalyzedBuild { superJumpTimeTotal: Stat; }; } + +export type SpecialEffectType = typeof SPECIAL_EFFECTS[number]["type"]; diff --git a/app/modules/analyzer/useAnalyzeBuild.ts b/app/modules/analyzer/useAnalyzeBuild.ts index 18e68b078..4d7deed30 100644 --- a/app/modules/analyzer/useAnalyzeBuild.ts +++ b/app/modules/analyzer/useAnalyzeBuild.ts @@ -6,9 +6,12 @@ import { type MainWeaponId, mainWeaponIds, abilities, + isAbility, } from "../in-game-lists"; import type { AbilityType, AbilityWithUnknown } from "../in-game-lists/types"; +import { applySpecialEffects, SPECIAL_EFFECTS } from "./specialEffects"; import { buildStats } from "./stats"; +import type { SpecialEffectType } from "./types"; import { buildToAbilityPoints } from "./utils"; const UNKNOWN_SHORT = "U"; @@ -18,19 +21,37 @@ export function useAnalyzeBuild() { const mainWeaponId = validatedWeaponIdFromSearchParams(searchParams); const build = validatedBuildFromSearchParams(searchParams); + const ldeIntensity = validatedLdeIntensityFromSearchParams(searchParams); + const effects = validatedEffectsFromSearchParams({ searchParams, build }); - const setMainWeaponId = (weaponId: MainWeaponId) => - setSearchParams({ weapon: String(weaponId), build: serializeBuild(build) }); - const setBuild = (newBuild: BuildAbilitiesTupleWithUnknown) => + const handleChange = ({ + newMainWeaponId = mainWeaponId, + newBuild = build, + newLdeIntensity = ldeIntensity, + newEffects = effects, + }: { + newMainWeaponId?: MainWeaponId; + newBuild?: BuildAbilitiesTupleWithUnknown; + newLdeIntensity?: number; + newEffects?: Array; + }) => { setSearchParams({ + weapon: String(newMainWeaponId), build: serializeBuild(newBuild), - weapon: String(mainWeaponId), + lde: String(newLdeIntensity), + effect: newEffects, }); + }; - const abilityPoints = React.useMemo( - () => buildToAbilityPoints(build), - [build] - ); + const abilityPoints = React.useMemo(() => { + const buildsAbilityPoints = buildToAbilityPoints(build); + + return applySpecialEffects({ + abilityPoints: buildsAbilityPoints, + effects, + ldeIntensity, + }); + }, [build, ldeIntensity, effects]); const analyzed = React.useMemo( () => @@ -43,9 +64,8 @@ export function useAnalyzeBuild() { return { build, - setBuild, mainWeaponId, - setMainWeaponId, + handleChange, analyzed, abilityPoints, }; @@ -121,3 +141,49 @@ function validateAbility( throw new Error("Invalid ability"); } + +const MAX_LDE_INTENSITY = 21; +function validatedLdeIntensityFromSearchParams(searchParams: URLSearchParams) { + const ldeIntensity = searchParams.get("lde") + ? Number(searchParams.get("lde")) + : null; + + if ( + !ldeIntensity || + !Number.isInteger(ldeIntensity) || + ldeIntensity < 0 || + ldeIntensity > MAX_LDE_INTENSITY + ) { + return 0; + } + + return ldeIntensity; +} + +function validatedEffectsFromSearchParams({ + searchParams, + build, +}: { + searchParams: URLSearchParams; + build: BuildAbilitiesTupleWithUnknown; +}) { + const result: Array = []; + + const effects = searchParams.getAll("effect"); + const effectsNoDuplicates = [...new Set(effects)]; + + for (const effect of effectsNoDuplicates) { + const effectObj = SPECIAL_EFFECTS.find((e) => e.type === effect); + if (!effectObj) continue; + + // e.g. even if OG effect is active in state + // it can't be on unless build has OG + if (isAbility(effect) && !build.flat().includes(effect)) { + continue; + } + + result.push(effect as SpecialEffectType); + } + + return result; +} diff --git a/app/modules/in-game-lists/index.ts b/app/modules/in-game-lists/index.ts index d7179a298..8fd94e3f9 100644 --- a/app/modules/in-game-lists/index.ts +++ b/app/modules/in-game-lists/index.ts @@ -14,3 +14,4 @@ export type { SubWeaponId, SpecialWeaponId, } from "./types"; +export { isAbility } from "./utils"; diff --git a/app/modules/in-game-lists/utils.ts b/app/modules/in-game-lists/utils.ts new file mode 100644 index 000000000..c44e9c085 --- /dev/null +++ b/app/modules/in-game-lists/utils.ts @@ -0,0 +1,6 @@ +import { abilities } from "./abilities"; +import type { Ability } from "./types"; + +export function isAbility(value: string): value is Ability { + return Boolean(abilities.some((a) => a.name === value)); +} diff --git a/app/routes/analyzer.tsx b/app/routes/analyzer.tsx index 5bc7b7c56..363b55b9f 100644 --- a/app/routes/analyzer.tsx +++ b/app/routes/analyzer.tsx @@ -32,8 +32,7 @@ export const handle = { export default function BuildAnalyzerPage() { const { t } = useTranslation(["analyzer", "common"]); useSetTitle(t("common:pages.buildAnalyzer")); - const { build, setBuild, mainWeaponId, setMainWeaponId, analyzed } = - useAnalyzeBuild(); + const { build, mainWeaponId, handleChange, analyzed } = useAnalyzeBuild(); // xxx: remove before prod if (process.env.NODE_ENV === "production") return
Coming soon :)
; @@ -48,7 +47,10 @@ export default function BuildAnalyzerPage() { inputName="weapon" initialWeaponId={mainWeaponId} onChange={(opt) => - opt && setMainWeaponId(Number(opt.value) as MainWeaponId) + opt && + handleChange({ + newMainWeaponId: Number(opt.value) as MainWeaponId, + }) } className="w-full-important" clearsInputOnFocus @@ -56,7 +58,10 @@ export default function BuildAnalyzerPage() { - + handleChange({ newBuild })} + />
{t("analyzer:patch")} {CURRENT_PATCH}