Effect and LDE intensity in Search Params

This commit is contained in:
Kalle
2022-09-16 17:59:06 +03:00
parent d07bf0af86
commit cefb55d19f
6 changed files with 96 additions and 15 deletions

View File

@@ -2,7 +2,7 @@ import type { AbilityPoints } from "./types";
const MAX_AP = 57;
const SPECIAL_EFFECTS = [
export const SPECIAL_EFFECTS = [
{
type: "OG",
values: [

View File

@@ -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"];

View File

@@ -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<SpecialEffectType>;
}) => {
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<SpecialEffectType> = [];
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;
}

View File

@@ -14,3 +14,4 @@ export type {
SubWeaponId,
SpecialWeaponId,
} from "./types";
export { isAbility } from "./utils";

View File

@@ -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));
}

View File

@@ -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 <Main>Coming soon :)</Main>;
@@ -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() {
</div>
<WeaponInfoBadges analyzed={analyzed} />
</div>
<AbilitiesSelector selectedAbilities={build} onChange={setBuild} />
<AbilitiesSelector
selectedAbilities={build}
onChange={(newBuild) => handleChange({ newBuild })}
/>
<div className="analyzer__patch">
{t("analyzer:patch")} {CURRENT_PATCH}
</div>