44 lines
1.7 KiB
TypeScript
44 lines
1.7 KiB
TypeScript
import type { GameConfig } from "@deadhead/content";
|
||
import { MS_PER_HOUR, type RealTime } from "./clock";
|
||
import { LONG_HAUL_SKILL_ID, skillLevel, type SkillLevels } from "./pilot";
|
||
|
||
/**
|
||
* Pilot duty and rest (CR-004, decisions 0.5.42–0.5.46). Rest is derived from a
|
||
* stored rest-ends-at time, so nothing has to run when it ends.
|
||
*/
|
||
|
||
/** Game hours a pilot may fly before mandatory rest: base plus a Long Haul bonus. */
|
||
export function dutyLimit(skills: SkillLevels, config: GameConfig): number {
|
||
const longHaul = skillLevel(skills, LONG_HAUL_SKILL_ID);
|
||
return config.dutyLimitGameHours + longHaul * config.longHaulDutyBonusGameHours;
|
||
}
|
||
|
||
/** Whether a pilot is resting at real time `now`: until (not at) rest-ends-at. */
|
||
export function isResting(restEndsAt: RealTime | null, now: RealTime): boolean {
|
||
return restEndsAt !== null && now < restEndsAt;
|
||
}
|
||
|
||
/** Game hours of a trip from its real departure and arrival times. */
|
||
export function tripGameHours(
|
||
departureAt: RealTime,
|
||
arrivalAt: RealTime,
|
||
config: GameConfig,
|
||
): number {
|
||
return ((arrivalAt - departureAt) * config.timeCompression) / MS_PER_HOUR;
|
||
}
|
||
|
||
/** Duty hours after a trip: tutorial runs add nothing (decision 0.5.42). */
|
||
export function dutyAfterTrip(dutyHours: number, tripHours: number, tutorial: boolean): number {
|
||
return tutorial ? dutyHours : dutyHours + tripHours;
|
||
}
|
||
|
||
/** Whether duty at or over the limit forces rest on arrival (decision 0.5.44). */
|
||
export function needsRest(dutyHours: number, limit: number): boolean {
|
||
return dutyHours >= limit;
|
||
}
|
||
|
||
/** When a rest starting at real time `start` ends (decision 0.5.45). */
|
||
export function restEndsAt(start: RealTime, config: GameConfig): RealTime {
|
||
return start + (config.restGameHours * MS_PER_HOUR) / config.timeCompression;
|
||
}
|