소스 검색

Start passing AI stuff to where it belongs

Reddo 5 년 전
부모
커밋
81b67e8568
6개의 변경된 파일148개의 추가작업 그리고 84개의 파일을 삭제
  1. 17 0
      app/Elements/Classes/Say.ts
  2. 18 0
      app/Elements/Classes/Say/SayYou.ts
  3. 18 0
      app/Elements/Classes/Say/SayYour.ts
  4. 22 6
      app/World/Classes/AI.ts
  5. 45 49
      app/World/Classes/AI/AIGrudge.ts
  6. 28 29
      app/World/Classes/Action.ts

+ 17 - 0
app/Elements/Classes/Say.ts

@@ -36,12 +36,29 @@ class Say {
 
     private centered : boolean = false;
 
+    public static Mention (target : Thing, uppercase = true) : Array<any> {
+        if (target == WorldState.player) {
+            return [new SayYou(uppercase)];
+        } else {
+            return [new SayThe(uppercase), target];
+        }
+    }
+
+    public static YourTheir (target : Thing, uppercase = true) {
+        if (target == WorldState.player) {
+            return [new SayYour(uppercase)];
+        } else {
+            return [new SayHisHersIts(target, uppercase)];
+        }
+    }
+
     public constructor (...objs) {
         this.add(...objs);
     }
 
     public add (...objs : Array<Say | OneOf | Object | Printable | string | number | String | ((say : Say) => string)>) {
         this.sequence.push(...objs);
+        return this;
     }
 
     public remove (...objs) {

+ 18 - 0
app/Elements/Classes/Say/SayYou.ts

@@ -0,0 +1,18 @@
+class SayYou extends Say {
+    private node : Text = document.createTextNode("a ");
+    private uppercase = true;
+
+    public constructor (autoUppercase = true) {
+        super();
+        this.uppercase = autoUppercase;
+    }
+
+    public async getPureElements (say : Say) : Promise<Array<Element | Text>> {
+        this.node.nodeValue =  "you";
+        if (this.uppercase && say.currentParagraph.length == 0) {
+            this.node.nodeValue = this.node.nodeValue.charAt(0).toUpperCase()
+                + this.node.nodeValue.substr(1, this.node.nodeValue.length - 1);
+        }
+        return [this.node];
+    }
+}

+ 18 - 0
app/Elements/Classes/Say/SayYour.ts

@@ -0,0 +1,18 @@
+class SayYour extends Say {
+    private node : Text = document.createTextNode("a ");
+    private uppercase = true;
+
+    public constructor (autoUppercase = true) {
+        super();
+        this.uppercase = autoUppercase;
+    }
+
+    public async getPureElements (say : Say) : Promise<Array<Element | Text>> {
+        this.node.nodeValue =  "your";
+        if (this.uppercase && say.currentParagraph.length == 0) {
+            this.node.nodeValue = this.node.nodeValue.charAt(0).toUpperCase()
+                + this.node.nodeValue.substr(1, this.node.nodeValue.length - 1);
+        }
+        return [this.node];
+    }
+}

+ 22 - 6
app/World/Classes/AI.ts

@@ -41,6 +41,8 @@ class AI {
     public static talktoRules = new Rulebook<Thing>("Default Talk To Rules");
     public extraTalktoRules : Array<Rulebook<Thing>> = [];
 
+    public storedReaction : Action;
+
     public constructor (options : AIOptions) {
         for (let key in options) {
             this[key] = options[key];
@@ -55,6 +57,12 @@ class AI {
         let promise : Promise<Action>;
         let inCombat = false;
 
+        if (this.storedReaction != undefined) {
+            let result = this.storedReaction;
+            this.storedReaction = undefined;
+            return result;
+        }
+
         if (this.hostileTargets.length > 0) {
             for (let i = this.hostileTargets.length - 1; i >= 0; i--) {
                 if (this.actor.getRoom() == this.hostileTargets[i].getRoom()) {
@@ -135,6 +143,16 @@ class AI {
         this.hostilityLevels.splice(index, 1);
     }
 
+    public getHostilityTo (target : Thing) {
+        let index = this.hostilityTargets.indexOf(target);
+        if (index != -1) {
+            return this.hostilityLevels[index];
+        } else {
+            return 0;
+        }
+    }
+
+    // TODO: Make this a rulebook.
     public coolOff () {
         for (let i = this.hostilityTargets.length - 1; i >= 0; i--) {
             this.hostilityLevels[i] -= this.coolOffRate;
@@ -150,12 +168,10 @@ class AI {
         }
     }
 
-    public getHostilityTo (target : Thing) {
-        let index = this.hostilityTargets.indexOf(target);
-        if (index != -1) {
-            return this.hostilityLevels[index];
-        } else {
-            return 0;
+    // TODO: Make this a rulebook. This happens every time an aggressive action is done.
+    public getPoked (action : Action) {
+        if (this.actor instanceof Person) {
+            AIRules.getPoked(this.actor, action);
         }
     }
 }

+ 45 - 49
app/World/Classes/AI/AIGrudge.ts

@@ -11,60 +11,56 @@ module AIRules {
     export var resultRetaliate = new ContentMarker("I'll hit you once so you can see how you like it", true);
     export var resultHostile = new ContentMarker("I'll hit you until you drop dead.", true);
 
-    export function printGrudgeResult (aggressor : Thing, victim : Person, ...markers : Array<ContentMarker>) {
-        if (victim.isVisibleTo(WorldState.player)) {
-            let group = new ContentGroup();
-            let unit = new CombatPokeUnit();
-            group.addUnit(unit);
-            unit.setTarget(victim);
-            unit.setAggressor(aggressor);
-            unit.addMarker(...markers);
+    export function printGrudgeResult (aggressor : Thing, victim : Person, ...markers : Array<ContentMarker>) : Say {
+        let group = new ContentGroup();
+        let unit = new CombatPokeUnit();
+        group.addUnit(unit);
+        unit.setTarget(victim);
+        unit.setAggressor(aggressor);
+        unit.addMarker(...markers);
 
-            if (aggressor == WorldState.player) {
-                victim.AI.warnedTimes++;
-            }
-            Elements.CurrentTurnHandler.printAsContent(new Say(...CombatPokeDescription.getDescription(group)));
+        if (aggressor == WorldState.player) {
+            victim.AI.warnedTimes++;
         }
+        return new Say(...CombatPokeDescription.getDescription(group));
     }
 
-    export var Grudge = AI.rules.createAndAddRule({
-        name : "Grudge",
-        firstPriority : AIRules.PRIORITY_ACTING_ON_SITUATION,
-        priority : AIRules.PRIORITY_ACTING_ON_SITUATION - 3,
-        code : (runner : RulebookRunner<Person>) => {
-            let person = runner.noun;
-            for (let i = 0; i < TurnSequence.currentTurnActionsTargets.length; i++) {
-                if (TurnSequence.currentTurnActionsTargets[i] == person) {
-                    let action = TurnSequence.currentTurnActions[i];
-                    if (action.actingAgressively) {
-                        person.AI.addHostility(action.actor, action.aggressivenessRating);
-                        if (action.actor == WorldState.player) {
-                            person.reputation -= action.aggressivenessRating;
-                        }
+    // TODO: Make a rulebook called "ReactionTo", this is a rule that should be there with a condition of Action = ActingAggressively.
+    export function getPoked (person : Person, action : Action) {
+        if (person.AI.hostileTargets.includes(action.actor)) {
+            return; // Already hostile
+        }
+        person.AI.addHostility(action.actor, action.aggressivenessRating);
+        if (action.actor == WorldState.player) {
+            person.reputation -= action.aggressivenessRating;
+        }
 
-                        let ai = person.AI;
-                        let gain = ai.grudgeRate * action.aggressivenessRating;
-                        let actionLevel = actionMin;
-                        let result = resultNotHostile;
-                        if (ai.getHostilityTo(action.actor) > 100) {
-                            result = resultHostile;
-                        } else if (ai.retaliates && ai.getHostilityTo(action.actor) >= (ai.hostileThreshold / 2)) {
-                            result = resultRetaliate;
-                        }
-                        if (gain >= (ai.hostileThreshold / 2)) {
-                            actionLevel = actionMax;
-                        } else if (gain >= (ai.hostileThreshold / 4)) {
-                            actionLevel = actionMed;
-                        }
+        let ai = person.AI;
+        let response : Say;
+        let gain = ai.grudgeRate * action.aggressivenessRating;
+        let actionLevel = actionMin;
+        let result = resultNotHostile;
+        if (ai.getHostilityTo(action.actor) > 100) {
+            result = resultHostile;
+        } else if (ai.retaliates && ai.getHostilityTo(action.actor) >= (ai.hostileThreshold / 2)) {
+            result = resultRetaliate;
+        }
+        if (gain >= (ai.hostileThreshold / 2)) {
+            actionLevel = actionMax;
+        } else if (gain >= (ai.hostileThreshold / 4)) {
+            actionLevel = actionMed;
+        }
+        response = printGrudgeResult(action.actor, person, actionLevel, result);
 
-                        printGrudgeResult(action.actor, person, actionLevel, result);
-                        if (result == resultRetaliate) {
-                            return new ActionAttack(person, action.actor);
-                        }
-                        return new ActionWait(person); // we talked so we shouldn't move further
-                    }
-                }
-            }
+        let nAct : Action;
+        if (result == resultRetaliate) {
+            nAct = new ActionAttack(person, action.actor);
+            nAct.finalSay = response.add(Say.PARAGRAPH_BREAK);
+            nAct.finalSayOnEnd = false;
+        } else {
+            nAct = new ActionWait(person);
+            nAct.finalSay = response.add(Say.PARAGRAPH_BREAK);
         }
-    });
+        person.AI.storedReaction = nAct;
+    }
 }

+ 28 - 29
app/World/Classes/Action.ts

@@ -21,6 +21,9 @@ class Action {
     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;
@@ -88,6 +91,14 @@ class 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;
     }
 
@@ -197,32 +208,20 @@ Action.check.addRule(
 );
 
 // 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 : (rulebook : RulebookRunner<Action>) => {
-//             let action = <Action> rulebook.noun;
-//             let target = action.getNoun(0);
-//             let tai = (<Person> target).AI;
-//             tai.anger += action.aggressivenessRating * tai.grudgeRate;
-//             let cu = new CombatPokeUnit().setTarget(target);
-//             if (tai.anger < 10) {
-//                 cu.addMarker(CombatPokeResult.NOHEAT);
-//             } else if (tai.anger < 100) {
-//                 cu.addMarker(CombatPokeResult.ANNOYED);
-//             } else {
-//                 cu.addMarker(CombatPokeResult.AGGROED);
-//                 (<Person>target).AI.hostileTo.push(action.actor);
-//             }
-//
-//
-//             action.say.add(Say.PARAGRAPH_BREAK, ...CombatPokeDescription.getDescription(new ContentGroup(cu)));
-//         },
-//         conditions : (rulebook : RulebookRunner<Action>) => {
-//             let action = <Action> rulebook.noun;
-//             return action.actor == WorldState.player && action.actingAgressively && action.getNoun(0) instanceof Person && !action.getNoun(0).isHostileTo(action.actor) && action.getNoun(0).getHealthOnScale() > 0;
-//         }
-//     })
-// );
+Action.carry.addRule(
+    new Rule({
+        name : "Check any Action - Angery",
+        firstPriority : Rule.PRIORITY_LOWEST,
+        priority: Rule.PRIORITY_LOWEST,
+        code : (rulebook : RulebookRunner<Action>) => {
+            let action = <Action> rulebook.noun;
+            let target = action.getNoun(0);
+            let tai = (<Person> target).AI;
+            tai.getPoked(action);
+        },
+        conditions : (rulebook : RulebookRunner<Action>) => {
+            let action = <Action> rulebook.noun;
+            return action.actingAgressively && action.getNoun(0) instanceof Person;
+        }
+    })
+);