/** * Represents the abstract idea of a Note, for example in a note chart you load from a text file, etc. */ export interface ChartNote { id: string; ms: number; code: Code; dependsOn?: string; } /** * Definition of a timing window. * name: "fanastic", "exellent", etc * * windowMs: size of window in ms. If a window is 22ms, * that means a note can be hit +- 11ms either side. * For example, if the windowMs is 22ms, and the note should be * hit at 300ms, an input at 289ms or 311m are within the window, * but 288ms and 312ms are not. */ export interface TimingWindow { name: string; windowMs: number; } export interface Chart { notes: ChartNote[]; } export interface EngineConfiguration { maxHitWindow: number; timingWindows: TimingWindow[] | undefined; } interface CreateChart { offset: number; notes: ChartNote[]; } /** * Creates a new chart. * Handles things like offsetting the notes. */ export declare function createChart(args: CreateChart): Chart; /** * An actual note used by the engine. * It has all the properties of a ChartNote, and some * gameplay specific ones such as when it was hit, if it can be hit, etc. */ export interface GameNote extends ChartNote { canHit: boolean; hitTiming?: number; hitAt?: number; timingWindowName: string | undefined; } /** * Represents an input from the user. * ms is the time of the input in millseconds since * the start of the game. * Code represents the key - this can be a virtual key, too. */ export interface Input { ms: number; code: string; } /** * Finds the "nearest" note given an input and a chart for scoring. */ export declare function nearestNote(input: Input, chart: Chart): ChartNote | undefined; /** * Get the difference between the time the note should have been hit * and the actual time it was hit. * Useful for scoring systems. * * If a note depends on a previous one, it's a "hold note". We assume * if the user hit that note, it's during a "hold", which means we * aware them perfect timing. A hold note is considered perfect if it was held - * this means hitting it anywhere in the valid window. */ export declare function judge(input: Input, note: ChartNote): number; export interface GameChart { notes: Map; } /** * Represents the current state of the game engine. */ export interface World { chart: GameChart; startTime: number; time: number; inputs: Input[]; } export interface JudgementResult { noteId: string; timing: number; time: number; timingWindowName: string | undefined; } interface JudgeInput { input: Input; chart: Chart; maxWindow: number; timingWindows: TimingWindow[] | undefined; } /** * Given an input and a chart, see if there is a note nearby and judge * how accurately the player hit it. */ export declare function judgeInput({ input, chart, maxWindow, timingWindows }: JudgeInput): JudgementResult | undefined; /** * Create a new "world", which represents the play-through of one chart. */ export declare function initGameState(chart: Chart): GameChart; interface PreviousFrameMeta { judgementResults: JudgementResult[]; } export interface UpdatedGameState { chart: GameChart; previousFrameMeta: PreviousFrameMeta; } /** * Returns a new chart and relevant data, given the existing state of the world. * * The only way the world changes is via a user input. * Given X world and Y input, the new world will always be Z. * That is to say the world in the engine is deterministic - no side effects. * * If there is no user input - that is, `inputs` is an empty array, the new chart will be identical to the previous one. */ export declare function updateGameState(world: World, config: EngineConfiguration): UpdatedGameState; export {};