mirror of
https://github.com/Sendouc/sendou.ink.git
synced 2026-08-22 19:16:09 -05:00
Effect and LDE intensity in Search Params
This commit is contained in:
@@ -2,7 +2,7 @@ import type { AbilityPoints } from "./types";
|
||||
|
||||
const MAX_AP = 57;
|
||||
|
||||
const SPECIAL_EFFECTS = [
|
||||
export const SPECIAL_EFFECTS = [
|
||||
{
|
||||
type: "OG",
|
||||
values: [
|
||||
|
||||
@@ -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"];
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -14,3 +14,4 @@ export type {
|
||||
SubWeaponId,
|
||||
SpecialWeaponId,
|
||||
} from "./types";
|
||||
export { isAbility } from "./utils";
|
||||
|
||||
6
app/modules/in-game-lists/utils.ts
Normal file
6
app/modules/in-game-lists/utils.ts
Normal 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));
|
||||
}
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user