UNPKG

@cruncheevos/core

Version:

Parse and generate achievements and leaderboards for RetroAchievements.org

375 lines (374 loc) 13.2 kB
import { Condition } from './condition.js'; type ConditionBuilderInput = Array<boolean | Condition.Input | ConditionBuilder>; type DefineFunction = ((...args: ConditionBuilderInput) => ConditionBuilder) & { /** * Same as calling `new Condition()` * * Can be useful if you need to reuse the condition but have it slightly different * * @example * import { define as $ } from '@cruncheevos/core' * * const isNTSC = $.one(['', 'Mem', '24bit', 0x9e1e, '=', 'Value', '', 0x373030]) * const notNTSC = isNTSC.with({ cmp: '!=' }) */ one: (arg: Condition.Input) => Condition; /** * Allows to generate conditions for comparing strings * * The string is split into numeric chunks, little endian, up to 32bit, * which are provided to the supplied callback. The final result is also * wrapped with `andNext` * * Internally, TextEncoder is used and the input is treated as UTF-8 * * If you need to treat input as UTF-16, currently you need to convert it to UTF-16 yourself * * @example * import { define as $ } from '@cruncheevos/core' * * $.str( * 'abcde', * (size, value) => $( * ['AddAddress', 'Mem', '32bit', 0xcafe], * ['AddAddress', 'Mem', '32bit', 0xfeed], * ['', 'Mem', size, 0xabcd, '=', ...value], * ) * ) * // "I:0xXcafe_I:0xXfeed_N:0xXabcd=1684234849_I:0xXcafe_I:0xXfeed_0xHabcd=101" * // abcd = 0x64636261 = 1684234849 * // e = 0x65 = 101 */ str: (input: string, callback: (s: Condition.Size, v: ['Value', '', number]) => ConditionBuilder) => ConditionBuilder; }; /** * Function providing versatile way to define conditions, * returns instance of ConditionBuilder class * * @example * import { define as $ } from '@cruncheevos/core' * let someParameter = false * * $( * ['', 'Mem', '32bit', 0xCAFE, '=', 'Value', '', 1], * '0=2' * ).trigger( * '0=3', * // condition below will not be included because * // the expression evaluated to falsy value * someParameter && '0=4', * ).toString() // 0xXcafe=1_0=2_T:0=3 */ export declare const define: DefineFunction; /** * Same as {@link define}, but starts the condition chain * by wrapping the passed conditions with Trigger flag * * @example * import { trigger } from '@cruncheevos/core' * trigger('0=1', '0=2').toString() // T:0=1_T:0=2 */ export declare const trigger: (...args: ConditionBuilderInput) => ConditionBuilder; /** * Same as {@link define}, but starts the condition chain * by wrapping the passed conditions with ResetIf flag * * @example * import { resetIf } from '@cruncheevos/core' * resetIf('0=1', '0=2').toString() // R:0=1_R:0=2 */ export declare const resetIf: (...args: ConditionBuilderInput) => ConditionBuilder; /** * Same as {@link define}, but starts the condition chain * by wrapping the passed conditions with PauseIf flag * * @example * import { pauseIf } from '@cruncheevos/core' * pauseIf('0=1', '0=2').toString() // P:0=1_P:0=2 */ export declare const pauseIf: (...args: ConditionBuilderInput) => ConditionBuilder; /** * Same as {@link define}, but starts the condition chain * by wrapping the passed conditions with AddHits flag * * @example * import { addHits } from '@cruncheevos/core' * addHits('0=1', '0=2').toString() // C:0=1_C:0=2 */ export declare const addHits: (...args: ConditionBuilderInput) => ConditionBuilder; /** * Same as {@link define}, but starts the condition chain * by wrapping the passed conditions with SubHits flag * * @example * import { subHits } from '@cruncheevos/core' * subHits('0=1', '0=2').toString() // D:0=1_D:0=2 */ export declare const subHits: (...args: ConditionBuilderInput) => ConditionBuilder; /** * Same as {@link define}, but starts the condition chain * by wrapping the passed conditions with Measured flag * * @example * import { measured } from '@cruncheevos/core' * measured('0=1', '0=2').toString() // M:0=1_M:0=2 */ export declare const measured: (...args: ConditionBuilderInput) => ConditionBuilder; /** * Same as {@link define}, but starts the condition chain * by wrapping the passed conditions with Measured% flag * * RAIntegration converts Measured flags to Measured% if *Track as %* checkbox is ticked * * @example * import { measuredPercent } from '@cruncheevos/core' * measuredPercent('0=1', '0=2').toString() // G:0=1_G:0=2 */ export declare const measuredPercent: (...args: ConditionBuilderInput) => ConditionBuilder; /** * Same as {@link define}, but starts the condition chain * by wrapping the passed conditions with MeasuredIf flag * * @example * import { measuredIf } from '@cruncheevos/core' * measuredIf('0=1', '0=2').toString() // Q:0=1_Q:0=2 */ export declare const measuredIf: (...args: ConditionBuilderInput) => ConditionBuilder; /** * Same as {@link define}, but starts the condition chain * by wrapping the passed conditions with ResetNextIf flag * * @example * import { resetNextIf } from '@cruncheevos/core' * resetNextIf('0=1', '0=2').toString() // Z:0=1_Z:0=2 */ export declare const resetNextIf: (...args: ConditionBuilderInput) => ConditionBuilder; /** * Same as {@link define}, but starts the condition chain * by wrapping the passed conditions with AndNext flag * * The final condition will not have AndNext flag applied * unless it's followed by a chained method call, otherwise * codition will not work correctly that way * * @example * import { andNext } from '@cruncheevos/core' * andNext('0=1', '0=2').toString() // N:0=1_0=2 * andNext('0=1', '0=2').also('0=3').toString() // N:0=1_N:0=2_0=3 */ export declare const andNext: (...args: ConditionBuilderInput) => ConditionBuilder; /** * Same as {@link define}, but starts the condition chain * by wrapping the passed conditions with OrNext flag * * The final condition will not have OrNext flag applied * unless it's followed by a chained method call, otherwise * codition will not work correctly that way * * @example * import { orNext } from '@cruncheevos/core' * orNext('0=1', '0=2').toString() // O:0=1_0=2 * orNext('0=1', '0=2').also('0=3').toString() // O:0=1_O:0=2_0=3 */ export declare const orNext: (...args: ConditionBuilderInput) => ConditionBuilder; /** * Same as {@link define}, but sets 1 hit to the final * condition that was passed to the function * * @example * $('0=1').once( * andNext('0=2', '0=3') * ).toString() // 0=1_N:0=2_0=3.1. */ export declare const once: (...args: ConditionBuilderInput) => ConditionBuilder; export declare class ConditionBuilder { /** * Holds the conditions that were previously added * by calling the {@link define} function and class methods * @readonly */ conditions: Condition[]; constructor(); /** * Adds conditions wrapped with Trigger flag to the chain * * @example * import { define as $ } from '@cruncheevos/core' * $('0=1').trigger('0=2', '0=3').toString() // 0=1_T:0=2_T:0=3 */ trigger(...args: ConditionBuilderInput): this; /** * Adds conditions wrapped with ResetIf flag to the chain * * @example * import { define as $ } from '@cruncheevos/core' * $('0=1').resetIf('0=2', '0=3').toString() // 0=1_R:0=2_R:0=3 */ resetIf(...args: ConditionBuilderInput): this; /** * Adds conditions wrapped with PauseIf flag to the chain * * @example * import { define as $ } from '@cruncheevos/core' * $('0=1').pauseIf('0=2', '0=3').toString() // 0=1_P:0=2_P:0=3 */ pauseIf(...args: ConditionBuilderInput): this; /** * Adds conditions wrapped with AddHits flag to the chain * * @example * import { define as $ } from '@cruncheevos/core' * $('0=1').addHits('0=2', '0=3').toString() // 0=1_C:0=2_C:0=3 */ addHits(...args: ConditionBuilderInput): this; /** * Adds conditions wrapped with SubHits flag to the chain * * @example * import { define as $ } from '@cruncheevos/core' * $('0=1').subHits('0=2', '0=3').toString() // 0=1_D:0=2_D:0=3 */ subHits(...args: ConditionBuilderInput): this; /** * Adds conditions wrapped with Measured flag to the chain * * @example * import { define as $ } from '@cruncheevos/core' * $('0=1').measured('0=2', '0=3').toString() // 0=1_M:0=2_M:0=3 */ measured(...args: ConditionBuilderInput): this; /** * Adds conditions wrapped with Measured% flag to the chain * * RAIntegration converts Measured flags to Measured% if *Track as %* checkbox is ticked * * @example * import { define as $ } from '@cruncheevos/core' * $('0=1').measuredPercent('0=2', '0=3').toString() // 0=1_G:0=2_G:0=3 */ measuredPercent(...args: ConditionBuilderInput): this; /** * Adds conditions wrapped with Measured flag to the chain * * @example * import { define as $ } from '@cruncheevos/core' * $('0=1').measuredIf('0=2', '0=3').toString() // 0=1_Q:0=2_Q:0=3 */ measuredIf(...args: ConditionBuilderInput): this; /** * Adds conditions wrapped with ResetNextIf flag to the chain * * @example * import { define as $ } from '@cruncheevos/core' * $('0=1').resetNextIf('0=2', '0=3').toString() // 0=1_Z:0=2_Z:0=3 */ resetNextIf(...args: ConditionBuilderInput): this; /** * Adds conditions wrapped with AndNext flag to the chain * * The final condition in the chain will not have AndNext flag * applied, because the condition will not work correctly that way * * @example * import { define as $ } from '@cruncheevos/core' * $('0=1').andNext('0=2', '0=3').toString() // 0=1_N:0=2_0=3 * $('0=1') * .andNext('0=2', '0=3') * .resetIf('0=4').toString() // 0=1_N:0=2_N:0=3_R:0=4 */ andNext(...args: ConditionBuilderInput): this; /** * Adds conditions wrapped with OrNext flag to the chain * * The final condition in the chain will not have OrNext flag * applied, because the condition will not work correctly that way * * @example * import { define as $ } from '@cruncheevos/core' * $('0=1').orNext('0=2', '0=3').toString() // 0=1_O:0=2_0=3 * $('0=1') * .orNext('0=2', '0=3') * .resetIf('0=4').toString() // 0=1_O:0=2_O:0=3_R:0=4 */ orNext(...args: ConditionBuilderInput): this; /** * Adds conditions to the chain as is * * @example * import { define as $, resetIf } from '@cruncheevos/core' * resetIf('0=1', '0=2') * .also('0=3') * .toString() // R:0=1_R:0=2_0=3 */ also(...args: ConditionBuilderInput): this; /** * Adds conditions as is with final condition set to have 1 hit * * @example * import { define as $ } from '@cruncheevos/core' * $('0=1') * .once( * andNext('0=2', '0=3') * ).toString() // 0=1_N:0=2_0=3.1. */ once(...args: ConditionBuilderInput): this; [Symbol.iterator](): Generator<Condition, void, unknown>; /** * Returns new instance of ConditionBuilder with mapped conditions * * Accepts a callback function that acts similar to Array.prototype.map * * If any conditional condition was ignored, it will not appear in the callback * * @example * $('0=1', false && '0=2', '0=3') * .map((c, i) => c.with({ hits: i + 1 })) * .toString() // 0=1.1._0=3.2. */ map(cb: (c: Condition, idx: number, array: Condition[]) => Condition): ConditionBuilder; /** * Returns new instance of ConditionBuilder with different * values merged into last condition * * `lvalue` and `rvalue` can be specified as partial array, which can be less verbose * * Useful when combined with pointer chains * * @param {Condition.PartialMergedData} data Condition.PartialMergedData * * @example * $( * ['AddAddress', 'Mem', '32bit', 0xcafe], * ['AddAddress', 'Mem', '32bit', 0xbeef], * ['', 'Mem', '32bit', 0, '=', 'Value', '', 120], * ).withLast({ cmp: '!=', rvalue: { value: 9 } }) * .toString() // I:0xXcafe_I:0xXbeef_0xX0!=9 * * $( * ['AddAddress', 'Mem', '32bit', 0xcafe], * ['AddAddress', 'Mem', '32bit', 0xbeef], * ['', 'Mem', '32bit', 0, '=', 'Value', '', 120], * ).withLast({ cmp: '!=', rvalue: rvalue: ['Delta', '32bit', 0] }) * .toString() // I:0xXcafe_I:0xXbeef_0xX0!=d0xX0 */ withLast(data: Condition.PartialMergedData): ConditionBuilder; /** * Returns a string with raw condition code * * @example * $( * ['AndNext', 'Mem', '32bit', 0xCAFE, '=', 'Value', '', 5], * ['', 'Delta', '32bit', 0xCAFE, '=', 'Value', '', 4] * ).toString() // N:0xXcafe=5_d0xXcafe=4 */ toString(): string; /** * Same as {@link ConditionBuilder.prototype.toString toString()} * * @example * JSON.stringify({ conditions: $('0=1', '0=2') }) * // {"conditions":"0=1_0=2"} */ toJSON(): string; } export {};