1
0
Fork 0

feat(qualification): validate civilian hit results

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
Jason Fraley 2026-09-04 12:04:44 -04:00
parent 7d6a4bd671
commit dc9d2f4605

View file

@ -13,6 +13,7 @@ import {
MAX_SHOTS_FIRED,
MAX_HITS,
MAX_DESPAWNED_TARGETS,
MAX_CIVILIAN_HITS,
} from "@/lib/aim-trainer";
interface ActionResult<T = undefined> {
@ -40,6 +41,7 @@ export interface AimTrainerResultInput {
difficulty: string;
headshots: number;
torsoHits: number;
civilianHits: number;
shotsFired: number;
despawnedUnhitTargets: number;
}
@ -71,12 +73,14 @@ export async function submitAimTrainerResult(
return { success: false, error: "Invalid difficulty." };
}
const { headshots, torsoHits, shotsFired, despawnedUnhitTargets } = input;
const { headshots, torsoHits, civilianHits, shotsFired, despawnedUnhitTargets } = input;
if (
!Number.isInteger(headshots) ||
headshots < 0 ||
!Number.isInteger(torsoHits) ||
torsoHits < 0 ||
!Number.isInteger(civilianHits) ||
civilianHits < 0 ||
!Number.isInteger(shotsFired) ||
shotsFired < 0 ||
!Number.isInteger(despawnedUnhitTargets) ||
@ -91,9 +95,12 @@ export async function submitAimTrainerResult(
if (hits > MAX_HITS) {
return { success: false, error: "Too many hits." };
}
if (hits > shotsFired) {
if (headshots + torsoHits + civilianHits > shotsFired) {
return { success: false, error: "Hits cannot exceed shots fired." };
}
if (civilianHits > MAX_CIVILIAN_HITS) {
return { success: false, error: "Too many civilian hits." };
}
if (despawnedUnhitTargets > MAX_DESPAWNED_TARGETS) {
return { success: false, error: "Too many despawned targets." };
}
@ -129,7 +136,13 @@ export async function submitAimTrainerResult(
const current = progression.minigames?.aimTrainer ?? {};
const accuracy = calculateAimTrainerAccuracy(hits, shotsFired, despawnedUnhitTargets);
const score = calculateAimTrainerScore(headshots, torsoHits, shotsFired, despawnedUnhitTargets);
const score = calculateAimTrainerScore(
headshots,
torsoHits,
shotsFired,
despawnedUnhitTargets,
civilianHits,
);
const difficultyBestScoreKey = `${input.difficulty}BestScore` as
| "recruitBestScore"
@ -204,6 +217,7 @@ export async function submitAimTrainerResult(
difficulty: input.difficulty,
score,
accuracy,
civilianHits,
xpEarned: xp,
bestScore,
difficultyBestScore,