feat: v0.11.0 — map interactions per PLAN.md: expanded airport popup (approx local time + deterministic generated weather), animated plane markers from /api/state polls with status popups, active contract route lines (pending dashed vs in-flight solid); pure libs lib/weather.ts, lib/localTime.ts, lib/mapData.ts
This commit is contained in:
@@ -0,0 +1,47 @@
|
||||
import { mulberry32 } from './game/seed';
|
||||
|
||||
// Pure deterministic per-airport weather (v0.11.0) — display-only per PLAN.md, no
|
||||
// gameplay effects. The same ICAO always yields the same weather (stable across
|
||||
// polls and sessions); an optional dayKey varies it by sim-day when wanted.
|
||||
|
||||
export type WeatherCondition = 'Clear' | 'Cloudy' | 'Rain' | 'Fog';
|
||||
|
||||
export interface AirportWeather {
|
||||
condition: WeatherCondition;
|
||||
// Meteorological convention: direction the wind blows FROM, degrees true [0, 360).
|
||||
windDirDeg: number;
|
||||
windKt: number;
|
||||
visibilityM: number;
|
||||
}
|
||||
|
||||
// FNV-1a 32-bit — cheap, stable string hash (no Math.random, no Date anywhere).
|
||||
function fnv1a(s: string): number {
|
||||
let h = 0x811c9dc5;
|
||||
for (let i = 0; i < s.length; i++) {
|
||||
h ^= s.charCodeAt(i);
|
||||
h = Math.imul(h, 0x01000193);
|
||||
}
|
||||
return h >>> 0;
|
||||
}
|
||||
|
||||
export function weatherFor(icao: string, dayKey?: number): AirportWeather {
|
||||
const seed = (fnv1a(icao) ^ (dayKey === undefined ? 0 : Math.imul(dayKey | 0, 0x9e3779b9))) >>> 0;
|
||||
const rng = mulberry32(seed);
|
||||
|
||||
const c = rng();
|
||||
let condition: WeatherCondition;
|
||||
if (c < 0.45) condition = 'Clear';
|
||||
else if (c < 0.75) condition = 'Cloudy';
|
||||
else if (c < 0.92) condition = 'Rain';
|
||||
else condition = 'Fog';
|
||||
|
||||
const windDirDeg = Math.floor(rng() * 360);
|
||||
const windKt = Math.round(2 + rng() * 28); // 2–30 kt
|
||||
|
||||
let visibilityM: number;
|
||||
if (condition === 'Fog') visibilityM = 500 + Math.floor(rng() * 1500); // 0.5–2 km
|
||||
else if (condition === 'Rain') visibilityM = 4000 + Math.floor(rng() * 6000); // 4–10 km
|
||||
else visibilityM = 8000 + Math.floor(rng() * 32000); // 8–40 km
|
||||
|
||||
return { condition, windDirDeg, windKt, visibilityM };
|
||||
}
|
||||
Reference in New Issue
Block a user