mirror of
https://github.com/Sendouc/sendou.ink.git
synced 2026-07-15 07:43:44 -05:00
89 lines
2.9 KiB
TypeScript
89 lines
2.9 KiB
TypeScript
import { specialWeaponParams } from "~/features/build-analyzer/core/utils";
|
|
import type { SpecialWeaponId } from "~/modules/in-game-lists/types";
|
|
import { specialWeaponIds } from "~/modules/in-game-lists/weapon-ids";
|
|
import {
|
|
calculateGroundRange,
|
|
simulateTrajectoryPoints,
|
|
type TrajectoryParams,
|
|
} from "./weapon-range";
|
|
|
|
const DEFAULT_BRAKE_AIR_RESIST = 0.36;
|
|
const DEFAULT_BRAKE_GRAVITY = 0.07;
|
|
const DEFAULT_BRAKE_TO_FREE_FRAME = 4;
|
|
const DEFAULT_FREE_GRAVITY = 0.016;
|
|
const DEFAULT_FREE_AIR_RESIST = 0;
|
|
|
|
export interface SpecialWeaponRangeResult {
|
|
/** Radius of the range circle, in game distance units. */
|
|
range: number;
|
|
/** Extra outer radius covered by the projectile's blast, in game distance units. */
|
|
blastRadius?: number;
|
|
rangeType: "projectile" | "radius";
|
|
}
|
|
|
|
/**
|
|
* Range circle definition for a special weapon, or `null` when the special has no meaningful
|
|
* range to draw. The underlying values come from `weapon-params.ts` (populated by
|
|
* `scripts/create-analyzer-json.ts`): projectile specials reuse the main weapon trajectory
|
|
* model, the rest carry a single effect radius.
|
|
*/
|
|
export function getSpecialWeaponRange(
|
|
specialWeaponId: SpecialWeaponId,
|
|
): SpecialWeaponRangeResult | null {
|
|
const params = specialWeaponParams(specialWeaponId);
|
|
|
|
if (params.Range_Radius !== undefined) {
|
|
return { range: params.Range_Radius, rangeType: "radius" };
|
|
}
|
|
|
|
if (params.Range_Distance !== undefined) {
|
|
return {
|
|
range: params.Range_Distance,
|
|
blastRadius: params.Range_BlastRadius,
|
|
rangeType: "projectile",
|
|
};
|
|
}
|
|
|
|
if (params.Range_SpawnSpeed === undefined) return null;
|
|
|
|
const trajectoryParams: TrajectoryParams = {
|
|
spawnSpeed: params.Range_SpawnSpeed,
|
|
goStraightStateEndMaxSpeed:
|
|
params.Range_GoStraightStateEndMaxSpeed ?? params.Range_SpawnSpeed,
|
|
goStraightToBrakeStateFrame: params.Range_GoStraightToBrakeStateFrame ?? 4,
|
|
freeGravity: params.Range_FreeGravity ?? DEFAULT_FREE_GRAVITY,
|
|
freeAirResist: params.Range_FreeAirResist ?? DEFAULT_FREE_AIR_RESIST,
|
|
brakeAirResist: params.Range_BrakeAirResist ?? DEFAULT_BRAKE_AIR_RESIST,
|
|
brakeGravity: params.Range_BrakeGravity ?? DEFAULT_BRAKE_GRAVITY,
|
|
brakeToFreeFrame:
|
|
params.Range_BrakeToFreeStateFrame ?? DEFAULT_BRAKE_TO_FREE_FRAME,
|
|
};
|
|
|
|
const range = calculateGroundRange(
|
|
simulateTrajectoryPoints(trajectoryParams),
|
|
);
|
|
|
|
return {
|
|
range,
|
|
blastRadius: params.Range_BlastRadius,
|
|
rangeType: "projectile",
|
|
};
|
|
}
|
|
|
|
export interface SpecialWeaponWithRange extends SpecialWeaponRangeResult {
|
|
specialWeaponId: SpecialWeaponId;
|
|
}
|
|
|
|
/**
|
|
* Every special weapon that has a range to draw, widest first. Specials without a meaningful
|
|
* range circle are omitted.
|
|
*/
|
|
export function getSpecialsWithRange(): SpecialWeaponWithRange[] {
|
|
return specialWeaponIds
|
|
.flatMap((specialWeaponId): SpecialWeaponWithRange[] => {
|
|
const result = getSpecialWeaponRange(specialWeaponId);
|
|
return result ? [{ specialWeaponId, ...result }] : [];
|
|
})
|
|
.sort((a, b) => b.range - a.range);
|
|
}
|