Getting trigger inside chat action

Developers
2010-11-16
2013-06-06
  • Zlatan Momic
    Zlatan Momic
    2010-11-16

    I'm trying to make NPC react on dynamic List of triggers. So I can use just one "add" method and control logic inside ChatAction. Inside chat action I can find players input with: sentence.getNormalized(). Question is how to get corresponding original trigger from dynamic List which triggered chat action?

    In code below if you type: "cubo" instead of "cube" chat action will fire but original trigger "Cube" will not be found.
    Is there any better way so every time chat action is fired I can find original trigger from dynamic List that corresponds to input: sentence.getNormalized()?

    List<String> dynamicTriggers = Arrays.asList("Red apple", "Apple in bag", "Cube");
    npc.add(ConversationStates.ATTENDING, dynamicTriggers, ConversationStates.ATTENDING, null, new ChatAction() {
                public void fire(Player player, Sentence sentence, EventRaiser npc) {
                    System.out.println("Input: " + sentence.getNormalized());
            System.out.println("InputTriger: " + sentence.getTriggerExpression().getNormalized());
                    TriggerList triggers = new TriggerList(dynamicTriggers);
                    final Expression trigger = sentence.getTriggerExpression();
                    final Expression found = triggers.find(trigger);
                    if (found != null) {
                        System.out.println("OriginalTriger: " + found.getOriginal());
                        int foundIndex = triggers.indexOf(found);
                        System.out.println("TriggerFromList: " + dynamicTriggers.get(foundIndex));
                    }
                }
    });
    

    This is output:

    Input: cube
    InputTrigger: cube
    OriginalTrigger: Cube
    TriggerFromList: Cube OK!


    Input: cubo
    InputTrigger: cubo
    OriginalTriger: NOT FOUND!
    TriggerFromList: NOT FOUND!


    Input: apple
    InputTrigger: apple
    OriginalTrigger: Apple
    TriggerFromList: Apple in bag OK!


    Input: aple
    InputTrigger: aple
    OriginalTriger: NOT FOUND!
    TriggerFromList: NOT FOUND!


    Input: aple in ba
    InputTrigger: aple
    OriginalTriger: NOT FOUND!
    TriggerFromList: NOT FOUND!


    Input: aple in bag
    InputTriger: aple
    OriginalTriger: NOT FOUND!
    TriggerFromList: NOT FOUND!


    Input: apple in bag
    InputTrigger: apple
    OriginalTrigger: Apple
    TriggerFromList: Apple in bag OK!


    Input: red apple
    InputTrigger: red apple
    OriginalTrigger: Red apple
    TriggerFromList: Red apple OK!


     
  • Zlatan Momic
    Zlatan Momic
    2010-11-16

    Also, if there is new element "Apple on plate" inside dynamicTriggers added after "Apple in bag",
    output will be:


    Input: apple on plate
    InputTrigger: apple
    OriginalTrigger: Apple
    TriggerFromList: Apple in bag BAD!


    Because they have same trigger.

     
  • Martin Fuchs
    Martin Fuchs
    2010-11-16

    Yes, "Sentence.getTriggerExpression()" ist not the optimal solution to look for compound trigger expressions. It was only designed to process simple one-word-expressions. Instead it was planned to refactor trigger processing by using a sentence matching algorithm. It should be able to compare two Sentence objects (say ConversationParser.parse("apple in bag") and ConversationParser.parse("this apple in the bag") to understand user input in a smart way.

    As long as the matching code is not yet usable, there is a work around by using "sentence.getOriginalText()" to query for the complete original user input and compare this for example with "apple in bag".

     
  • Zlatan Momic
    Zlatan Momic
    2010-11-16

    Yes, I noticed getOriginalText(). Using it will give me exactly the player's input for example "cubo" and comparing it with equals will not give me compound trigger. So it will work only when player types trigger exactly with no mistakes "cube", although chat action will fire on similar trigger as well as exact one.

    Is there any method I should use to compare "sentence.getOriginalText()" with some trigger for example "cube", which will include similar triggers and mistakes like "cubo"?

     
  • Martin Fuchs
    Martin Fuchs
    2010-11-16

    You might have a look at the class games.stendhal.server.entity.npc.parser.SimilarExprMatcher and experiment a bit with it.
    It enables in-exact string comparison. There are a few test cases in SimilarExprMatcherTest you can take as examples to see how to use it. However this string matching is really not exact and it might have some unexpected effects.  :-)

     
  • Zlatan Momic
    Zlatan Momic
    2010-11-17

    Yes, SimilarExprMatcher was very helpful. Here is the code that works very well as far as I tested.

    public class SentenceList {
        private List<Sentence> sentences = new ArrayList<Sentence>();
        /**
         * Create a list of sentences from a String list.
         *
         * @param strings String list
         */
        public SentenceList(final List<String> strings) {
            for (final String text : strings) {
                sentences.add(ConversationParser.parse(text, new SimilarExprMatcher()));
            }
        }
        /**
         * Search for the given text in the list.
         *
         * @param text
         * @return original text of the matching sentence
         */
        public final String findFullMatch(final String text) {
            final ConversationContext ctx = new ConvCtxForMatchingSource();
            final Sentence candidate = ConversationParser.parse(text, ctx);
            for (Sentence sentence : sentences) {
                if (candidate.matchesFull(sentence)) {
                    return sentence.getOriginalText(); // this will return Null probably because of BUG in ExpressionMatcher->parseSentence(String text, final ConversationContext ctx) ***
                }
            }
            return null;
        }
    }
    // NPC initialization
                    List<String> stringTriggers = Arrays.asList("Red apple", "Apple in bag", "Cube"); 
                    SentenceList sentenceTriggers = new SentenceList(stringTriggers);
    // NPC ChatAction
    public void fire(Player player, Sentence sentence, EventRaiser npc) {
                    final String input = sentence.getOriginalText();
                    final String trigger = sentenceSymptoms.findFullMatch(input);
    }
    

    *** I solved this by setting sentence.originalText = ot; at the end of the method just like in ConversationParser->parse(String text, final ConversationContext ctx).

     
  • Martin Fuchs
    Martin Fuchs
    2010-11-19

    Thanks for your hint about the bug regarding returning null from getOriginaltext() when not using ConversionParser.parse(). It is now fixed in CVS, so you don't need the workaround with "ot" any more.

     


Anonymous


Cancel   Add attachments