123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227 |
- /// <reference path="Rulebook.ts" />
- /// <reference path="Rule.ts" />
- /// <reference path="Things/Person.ts" />
- /// <reference path="../../Elements/Classes/Say.ts" />
- class Action {
- public static check = new Rulebook<Action>("Check any Action");
- public static carry = new Rulebook<Action>("Carry out any Action");
- public extraChecks : Array<Rulebook<Action>> = [];
- public extraCarries : Array<Rulebook<Action>> = [];
- public _actor : Thing;
- public nouns : Array<Thing> = [];
- public say : Say = new Say();
- public actingAgressively = false;
- public aggressivenessRating = 1;
- public actingSubmissively = false;
- public requiresTurn = true;
- public requiresNoun = true;
- public requiresVisibility = true; // First noun must be visible and in the same room
- public allowedStances = [PersonStance.ALLFOURS, PersonStance.STANDING];
- public finalSay : Say;
- public finalSayOnEnd = true;
- public constructor (actor : Thing, ...nouns : Array<any>) {
- this.actor = actor;
- nouns.forEach((value, index, array) => {
- this.setNoun(index, value);
- });
- }
- public async execute () : Promise<Say> {
- this.say = new Say();
- let checkRulebooks = [];
- let carryRulebooks = [];
- let cClass = this.constructor;
- while (cClass != Action) {
- if ((<typeof Action> cClass).check != undefined) {
- checkRulebooks.push((<typeof Action> cClass).check);
- }
- if ((<typeof Action> cClass).carry != undefined) {
- carryRulebooks.push((<typeof Action> 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) {
- if (this.requiresTurn) {
- /**
- * Add to the list of actions performed in turn.
- * Notice the position of this thing: If the action failed, but an attempt was made, it still gets added to the board.
- * The importance of ths is, if you do something to annoy an NPC and you get stopped midway, they still get to react.
- */
- TurnSequence.addAction(this);
- }
- return;
- } else if(result instanceof Action) {
- console.debug(Rulebook.getIndentation() + "[ACTION] Instead of...");
- let originalNouns = this.nouns;
- await result.execute();
- this.say.add(result.say);
- this.nouns = result.nouns;
- // Reset to initial state
- this.nouns = originalNouns;
- return;
- }
- /**
- * Carry Out
- */
- await Action.carry.execute({
- noun : this
- }, ...carryRulebooks);
- /**
- * Add to the list of actions performed in turn.
- * Notice the position of this thing: if an action was replaced by another, it will instead add that action.
- */
- TurnSequence.addAction(this);
- if (this.finalSay != undefined) {
- if (this.finalSayOnEnd) {
- this.say.add(...this.finalSay.sequence);
- } else {
- this.say = new Say(...this.finalSay.sequence, ...this.say.sequence);
- }
- }
- return this.say;
- }
- get actor(): Thing {
- return this._actor;
- }
- set actor(value: Thing) {
- this._actor = value;
- }
- // TODO: The if shouldn't be necessary right? I don't wanna touch this right now.
- 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 = <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<Action>) => {
- let action = <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 - Stance",
- firstPriority : Rule.PRIORITY_HIGHEST,
- code : (rulebook : RulebookRunner<Action>) => {
- let action = <Action> rulebook.noun;
- let actor = action.actor;
- if (actor instanceof Person) {
- if (action.allowedStances.indexOf(actor.stance) == -1) {
- if (action.actor == WorldState.player) {
- action.say = new Say("You can't do that while ", PersonStanceNames[actor.stance], ", you need to be ", PersonStanceNames[action.allowedStances[0]], ".");
- }
- action.stop();
- return false;
- }
- }
- }
- })
- );
- Action.check.addRule(
- new Rule({
- name : "Check any Action - Requires Visibility",
- code : (rulebook : RulebookRunner<Action>) => {
- let action = <Action> rulebook.noun;
- let actor = action.actor;
- if (!action.getNoun(0).isVisibleTo(actor)) {
- return false;
- }
- },
- conditions : runner => {
- return runner.noun.requiresVisibility;
- }
- })
- );
- // TODO: Pass everything on here directly to the AI so that IT can handle this.
- Action.carry.addRule(
- new Rule({
- name : "Check any Action - Angery",
- firstPriority : Rule.PRIORITY_LOWEST,
- priority: Rule.PRIORITY_LOWEST,
- code : async (rulebook : RulebookRunner<Action>) => {
- let action = <Action> rulebook.noun;
- let target = action.getNoun(0);
- let tai = (<Person> target).AI;
- await tai.getPoked(action);
- },
- conditions : (rulebook : RulebookRunner<Action>) => {
- let action = <Action> rulebook.noun;
- return action.actingAgressively && action.getNoun(0) instanceof Person;
- }
- })
- );
|