///
///
///
class Action {
public static check = new Rulebook("Check any Action");
public static carry = new Rulebook("Carry out any Action");
public extraChecks : Array> = [];
public extraCarries : Array> = [];
public _actor : Thing;
public nouns : Array = [];
public say : Say = new Say();
public actingAgressively = false;
public actingSubmissively = false;
public requiresTurn = true;
public requiresNoun = true;
public requiresVisibility = true; // First noun must be visible and in the same room
public constructor (actor : Thing, ...nouns : Array) {
this.actor = actor;
nouns.forEach((value, index, array) => {
this.setNoun(index, value);
});
}
public async execute () : Promise {
this.say = new Say();
let checkRulebooks = [];
let carryRulebooks = [];
let cClass = this.constructor;
while (cClass != Action) {
if (( cClass).check != undefined) {
checkRulebooks.push(( cClass).check);
}
if (( cClass).carry != undefined) {
carryRulebooks.push(( cClass).carry);
}
cClass = Object.getPrototypeOf(cClass);
}
/**
* Check if action goes through
*/
let result = await Action.check.execute({
noun : this
}, ...checkRulebooks);
// There are now multiple results! A false result means a fail Check! But it can also return a new action!
if (result == false) {
return;
} else if(result instanceof Action) {
console.debug(Rulebook.getIndentation() + "[ACTION] Instead of...");
await result.execute();
this.say.add(result.say);
this.nouns = result.nouns;
return;
}
/**
* Carry Out
*/
await Action.carry.execute({
noun : this
}, ...carryRulebooks);
return this.say;
}
get actor(): Thing {
return this._actor;
}
set actor(value: Thing) {
this._actor = value;
}
public getNoun (n : number) : any {
if (this.nouns.length > n) {
return this.nouns[n];
}
return undefined;
}
public setNoun (n : number, noun : any) {
while (this.nouns.length < n) {
this.nouns.push(undefined);
}
this.nouns[n] = noun;
}
/**
* Needs to return a string explaining what the player will do if he does this action.
* For instance, ActionTaking should return something like return "take " + this.nouns[0].getName(),
* which would read as "take thing".
* remember that things implement PRINTABLE interface, so you can get their names.
* @returns {string}
*/
public getCommandText () {
return "do";
}
/**
* If an action is stopped, it means it failed so spectacularly that it didn't even begin.
* Which means if the player is doing it, it'll not take a turn.
*/
public stop () {
this.requiresTurn = false;
}
}
// Action.addCarryRule(new Rule({
// name : "Testing say in actions rule",
// priority : Rule.PRIORITY_LOWEST,
// firstPriority : Rule.PRIORITY_LOWEST,
// code : (rule, rulebook) => {
// let action = rulebook.noun;
// action.say.add("You do nothing all turn. What was the point, really?");
// }
// }))
Action.check.addRule(
new Rule({
name : "Check any Action - Requires Noun",
firstPriority : Rule.PRIORITY_HIGHEST,
code : (rulebook : RulebookRunner) => {
let action = rulebook.noun;
if (action.getNoun(0) == undefined) {
return false;
}
},
conditions : runner => {
return runner.noun.requiresNoun;
}
})
);
Action.check.addRule(
new Rule({
name : "Check any Action - Requires Visibility",
code : (rulebook : RulebookRunner) => {
let action = rulebook.noun;
let actor = action.actor;
if (!action.getNoun(0).isVisibleTo(actor)) {
return false;
}
},
conditions : runner => {
return runner.noun.requiresVisibility;
}
})
);