diff --git a/src/combat.ts b/src/combat.ts index 3ea5a2876c..eeb971c846 100644 --- a/src/combat.ts +++ b/src/combat.ts @@ -25,6 +25,7 @@ import { overlappingSkillNames, } from "./overlappingNames.js"; import { get, set } from "./property.js"; +import { notNullish } from "./utils.js"; const MACRO_NAME = "Script Autoattack Macro"; /** @@ -185,6 +186,14 @@ type Constructor = { new (): T }; export class InvalidMacroError extends Error {} +export type ElseIfComponent = { + predicate: PreBALLSPredicate; + macro: string | Macro; +}; +export type ElseTrain = + | ElseIfComponent[] + | [...ElseIfComponent[], undefined | string | Macro]; + /** * BALLS macro builder for direct submission to KoL. * Create a new macro with `new Macro()` and add steps using the instance methods. @@ -549,21 +558,45 @@ export class Macro { * * @param condition The BALLS condition for the if statement. * @param ifTrue Continuation if the condition is true. - * @param ifFalse Optional else-branch for the macro. + * @param elseTrain Spread array of { predicate, macro } elif entries, followed by an final bare string/Macro for the final Else. * @returns {Macro} This object itself. */ if_( condition: PreBALLSPredicate, ifTrue: string | Macro, - ifFalse?: string | Macro, + ...elseTrain: ElseTrain + ): this; + /** + * Add an "if" statement to this macro, followed by a long chain of "elif"s, followed optionally by an "else" + * + * @param elseTrain Spread array of { predicate, macro } elif entries, followed by an final bare string/Macro for the final Else. + * @returns {Macro} This object itself. + */ + if_(...elseTrain: ElseTrain): this; + if_( + leadingArg: PreBALLSPredicate | ElseIfComponent, + secondArg: typeof leadingArg extends ElseIfComponent + ? ElseIfComponent | undefined + : string | Macro, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + ...rest: any[] ): this { - this.step(`if ${Macro.makeBALLSPredicate(condition)}`).step(ifTrue); + if (!(typeof leadingArg === "object" && "predicate" in leadingArg)) { + this.step(`if ${Macro.makeBALLSPredicate(leadingArg)}`, secondArg); + } - if (ifFalse) { - this.step("else").step(ifFalse); + for (const elseEntry of (rest as ElseTrain[number][]).filter(notNullish)) { + if (typeof elseEntry === "object" && !(elseEntry instanceof Macro)) { + const { predicate, macro } = elseEntry; + this.step(`elif ${Macro.makeBALLSPredicate(predicate)}`).step(macro); + } else { + this.step("else").step(elseEntry); + } } - return this.step("endif"); + this.step("endif"); + + return this; } /** @@ -571,16 +604,16 @@ export class Macro { * * @param condition The BALLS condition for the if statement. * @param ifTrue Continuation if the condition is true. - * @param ifFalse Optional else-branch for the macro. + * @param elseTrain Spread array of { predicate, macro } elif entries, followed by an final bare string/Macro for the final Else. * @returns {Macro} This object itself. */ static if_( this: Constructor, condition: PreBALLSPredicate, ifTrue: string | Macro, - ifFalse?: string | Macro, + ...elseTrain: ElseTrain ): T { - return new this().if_(condition, ifTrue, ifFalse); + return new this().if_(condition, ifTrue, ...elseTrain); } /**