Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 42 additions & 9 deletions src/combat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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";
/**
Expand Down Expand Up @@ -185,6 +186,14 @@ type Constructor<T> = { 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.
Expand Down Expand Up @@ -549,38 +558,62 @@ 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;
}

/**
* Create a new macro with an "if" statement.
*
* @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_<T extends Macro>(
this: Constructor<T>,
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);
}

/**
Expand Down
Loading