Special jobs: data-driven special-status registry with priority status (ISS-073, v0.37.0)
CI / build + unit + e2e (pull_request) Failing after 7m56s
CI / build + unit + e2e (pull_request) Failing after 7m56s
This commit is contained in:
+18
-4
@@ -1,5 +1,6 @@
|
||||
import { haversineKm } from '@/lib/geo';
|
||||
import { PLANE_TYPES, STARTER_MODEL } from './catalog';
|
||||
import { pickSpecial, SPECIALS } from './specials';
|
||||
|
||||
// First-run seed. Everything here is a pure function of (airports, rng, nowMs)
|
||||
// so it is fully deterministic and unit-testable: the RNG is injected, never
|
||||
@@ -52,6 +53,8 @@ export interface SeedPackage {
|
||||
cargoCount: number;
|
||||
// Package weight in kg (v0.27.0, ISS-045) — unit weight × count with ±30% jitter.
|
||||
weightKg: number;
|
||||
// Special status (v0.37.0, ISS-073) — key into lib/game/specials.ts SPECIALS; null = none.
|
||||
special: string | null;
|
||||
deadlineSimTime: number;
|
||||
status: 'open';
|
||||
planeId: null;
|
||||
@@ -116,12 +119,14 @@ export function rewardFor(km: number, weightKg: number): number {
|
||||
// weight = unit weight × count with ±30% jitter (v0.27.0), deadline now + 6–72h
|
||||
// game time (or now + deadlineOffsetMs when given — used by the e2e test hook to
|
||||
// force a near-term expiry). The RNG call order per package is fixed: origin,
|
||||
// dest, cargoType, cargoCount, weight jitter, [deadline window].
|
||||
// dest, cargoType, cargoCount, weight jitter, [deadline window], [special].
|
||||
// v0.8.0: originIcao/destIcao optionally FORCE an endpoint (spawn coverage rule +
|
||||
// the e2e create-package hook); a forced endpoint consumes no RNG draws, so
|
||||
// callers that omit both get byte-identical behavior to before.
|
||||
// v0.27.0: weightKg optionally FORCES the package weight (e2e hook) — it skips the
|
||||
// jitter draw, same pattern as forced endpoints.
|
||||
// v0.37.0 (ISS-073): special optionally FORCES the special status (string or explicit null) —
|
||||
// it skips the appended pickSpecial draw; otherwise ~SPECIAL_SPAWN_CHANCE of packages roll one.
|
||||
export function generatePackage(input: {
|
||||
id: string;
|
||||
airports: SeedAirport[];
|
||||
@@ -131,6 +136,7 @@ export function generatePackage(input: {
|
||||
originIcao?: string;
|
||||
destIcao?: string;
|
||||
weightKg?: number;
|
||||
special?: string | null;
|
||||
}): SeedPackage {
|
||||
const { airports, rng, nowMs } = input;
|
||||
if (airports.length < 2) throw new Error('package generation needs at least two airports');
|
||||
@@ -165,17 +171,25 @@ export function generatePackage(input: {
|
||||
// Weight (v0.27.0): unit weight × count with ±30% jitter, integer kg — drawn AFTER
|
||||
// cargoCount so the fixed RNG order above holds; a forced weightKg skips the draw.
|
||||
const weightKg = input.weightKg ?? Math.round(UNIT_WEIGHT_KG[cargoType] * cargoCount * (0.7 + 0.6 * rng()));
|
||||
const deadlineMs =
|
||||
input.deadlineOffsetMs ?? (DEADLINE_MIN_HOURS + rng() * (DEADLINE_MAX_HOURS - DEADLINE_MIN_HOURS)) * 3_600_000;
|
||||
// Drawn deadline window — the existing draw, position unchanged; special scaling is applied
|
||||
// below AFTER the appended special draw so the fixed order above holds.
|
||||
const drawnWindowMs = (DEADLINE_MIN_HOURS + rng() * (DEADLINE_MAX_HOURS - DEADLINE_MIN_HOURS)) * 3_600_000;
|
||||
// v0.37.0 (ISS-073): special status — the appended draw at the END of the fixed order above; a
|
||||
// forced value (including explicit null) skips it, same pattern as the other overrides.
|
||||
const special = input.special !== undefined ? input.special : pickSpecial(rng);
|
||||
const mods = special !== null ? SPECIALS[special] : undefined;
|
||||
// Forced deadlines skip the special scaling — consistent with overrides skipping draws.
|
||||
const deadlineMs = input.deadlineOffsetMs ?? drawnWindowMs * (mods?.deadlineScale ?? 1);
|
||||
|
||||
return {
|
||||
id: input.id,
|
||||
originIcao: origin.icao,
|
||||
destIcao: dest.icao,
|
||||
reward: rewardFor(km, weightKg),
|
||||
reward: Math.round(rewardFor(km, weightKg) * (mods?.rewardMultiplier ?? 1)),
|
||||
cargoType,
|
||||
cargoCount,
|
||||
weightKg,
|
||||
special,
|
||||
deadlineSimTime: Math.round(nowMs + deadlineMs),
|
||||
status: 'open',
|
||||
planeId: null,
|
||||
|
||||
Reference in New Issue
Block a user