[Crossfire-wiki] [Crossfire DokuWiki] page changed: cfdialog

no-reply_wiki at metalforge.org no-reply_wiki at metalforge.org
Sat Nov 15 03:22:54 CST 2008


A page in your DokuWiki was added or changed. Here are the details:

Date        : 2008/11/15 03:22
User        : 
Edit Summary: Update to match current SVN revisions of CFDialog.py and npc_dialog.py.

@@ -7,43 +7,43 @@
  bother about complex programming, but just want to make a few
  dialogs that are better than the @match system used in the
  server.
  
- ===== How to use this. =====
+ =====What is CFDialog?=====
  
- First, you need to import DialogRule and Dialog classes. Add the
- following line at the beginning of your script:
+ This is a small set of utility classes, to help you create complex dialogs.  It is made for those who do not want to bother about complex programming, but just want to make a few dialogs that are better than the @match system used in the server.
  
- ''from CFDialog import DialogRule, Dialog''
+ =====How to use CFDialog=====
  
- Then, you can go to the dialogs themselves. A dialog is made of
- several rules. Each rule is made of keywords, preconditions,
- postconditions, answers and pre/postfunction.
+ First, create a script that imports the DialogRule and Dialog classes. Add the following line at the beginning of your script:
  
-   * **Keywords** are what the rule will be an answer to. For example, if you want a rule to be triggered when the player will say "hi", then "hi" is the keyword to use. You can associate more than a keyword to a rule by concatenating them with the "|" character. Finally, "*" is a special keyword that means: "match everything". "*" is useful to provide generic answers.
+   from CFDialog import DialogRule, Dialog
  
-   * **Answers** are what will be said when the rule is triggered. This is what the NPC replies to the player. Answers are stored in a list. When there is more than one answer in that list, one will be selected at random.
-     * Insert newlines in an answer with **\n**.
+ Next, build the dialog by creating a sequence of several rules made up of keywords, answers, preconditions, and postconditions.  Optionally, define prefunctions or postfunctions to enhance the capabilities of the rule.
  
-   * **Preconditions** are flags that must match for the rule to be triggered. Each precondition has a name and a value. The default value of a precondition is "0". The flags are stored into each player, and will survive between gaming sessions. They are useful to set the point in a dialog reached by a player - you can see those as an "NPC memory". All conditions must have a name and a value. The ":" and ";" characters are forbidden. For a rule to be triggered, all the player's flags should match the preconditions. If you give "*" as the value for a precondition, it means that there is no need to match it. A precondition is a list in the form: [key, value]. All preconditions are stored in a list. Note that you can use any string you want for the condition values, provided it doesn't contain ";" or ":".
+   * **Keywords** are what the rule answers to.  For example, if you want a rule to trigger when the player says ''hi'', then ''//hi//'' must appear in the keyword list.  One or more keywords are specified in a string list in the form **["keyword1", "keyword2" ...]**.  A ''*'' character is a special keyword that means: "match everything", and is useful to create rules that provide generic answers no matter what the player character says.
+     * **NOTE:**  Like the @match system, CFDialog converts both keywords and the things the player says to lowercase before checking for a match, so it is never necessary to include multiple keywords that only differ in case.
  
-   * **Postconditions** are the status changes to apply to the player's conditions after the rule has been triggered. Their format is similar to preconditions. A value of "*" means that the condition will not be touched.
+   * **Answers** are what the rule will respond, or say, to the player when it is triggered.  This is what the NPC replies to the player. Answers are stored in a list of one or more strings in the form **["Answer1", "Answer2" ...]**.  When there is more than one answer in that list, each time the rule is triggered, a single random reply will be selected from the list.
+     *NOTE:  Answers may contain line breaks.  To insert one, use "\n".
  
-   * A **prefunction** is an optional callback function that will be called when a rule's preconditions are all matched, but before the rule is validated.  The callback can do additional tests, and should return 1 to allow the rule to be selected, 0 to block the rule. The function arguments are the player and the actual rule being tested.
+   * **Preconditions** are flags that must match specific values in order for a rule to be triggered. These flags persist across gaming sessions and are useful for tracking the state of a conversation with an NPC.  Because of this, it is possible for the same word to elicit different NPC responses depending on how flags have been set.  If dialogs are set to use identical locations, the flags and preconditions can be used by other NPC dialogs so that other NPCs can detect that the player heard specific information from another NPC.  The flags can also be used to help an individual NPC remember what he has said to the player in the past.  Flag settings are stored in the player file, so they persist as long as the character exists in the game.  Each rule contains a list of one or more preconditions, and each of the individual preconditions is itself a list of a flag name and one or more values in the following format: **<nowiki>[["flag1", "value1", "value2" ...], ["flag2", "value3"] ...]</nowiki>** where **...** indicates that the pattern may be repeated. The flag name is always the first item in a precondition list.  ":" and ";" characters are forbidden in the flag names and values.  For a rule to be triggered, all its preconditions must be satisfied by settings in the player file.  To satisfy a precondition, one of the its values must match the identified flag setting in the player file. The default value of any precondition that has not been specifically set in the player file is "0".  If one of the precondition values is set to "*", a match is not required.
  
-   * A **postfunction** is an optional callback that is called when a rule has been applied, and after the message is said. It can do additional custom .processing. The function arguments are the player and the actual rule having been used.
+   * **Postconditions** are state changes to apply to the player file flags after the rule triggers. The postcondition is a nested list that has the same format as the precondition list except that each postcondition list only contains one value.  This is because the other main difference is that whereas a precondition checks a player file to see if a flag has a certain value, the postcondition causes a value to be stored into the player file, and it does not make sense to store more than one value into a single flag.  A value of "*" means that the player file flag will not be changed.
  
- Once you have defined your rules, you have to assemble them into a dialog. Each dialog involves somebody who triggers it, somebody who answers, and has a unique name so it cannot be confused with other dialogs.
+   * **Prefunctions** are an optional callback function that will be called when a rule's preconditions are all matched, but before the rule is validated.  The callback can do additional tests, and should return 1 to allow the rule to be selected, or 0 to block the rule.  The function arguments are the player and the actual rule being tested.
  
- Typically, the "one who triggers" will be the player, and the "one who answers" is an NPC the player was taking to. You are free to chose whatever you want for the dialog name, as long as it contains no space or special characters, and is not used by another dialog. You can then add the rules you created to the dialog. Rules are parsed in a given order, so you must add the most generic answer last.
+   * **Postfunctions** are an optional callback that is called when a rule has been applied, and after the message is said. It can do additional custom processing. The function arguments are the player and the actual rule having been used.
  
- Like the @match system, CFDialog converts both match strings and the things the player says to lowercase before checking for a match.
+ Once the rules are all defined, assemble them into a dialog.  Each dialog involves somebody who triggers it, somebody who answers, and also a unique name so it cannot be confused with other dialogs.
+ 
+ Typically, the "one who triggers" will be the player, and the "one who answers" is an NPC the player was taking to. You are free to choose whatever you want for the dialog name, as long as it contains no whitespace or special characters, and as long as it is not used by another dialog.  You can then add the rules you created to the dialog. Rules are parsed in a given order, so you must add the most generic answer last.
  
  ===== A simple example =====
  
- I want to create a dialog for an old man. If I say "hello" or "hi" for the first time, grandpa will greet me. If I say it for the second time, he'll grumble (because he's like that, you know :)). I also need a generic answer if I say whatever else.
+ If I want to create a dialog for an old man, I might want him to respond to "hello" or "hi" differently the first time the player meets the NPC, and differently for subsequent encounters. In this example, grandpa greets the player cordially the first time, but grumbles subequent times (because he's like that, you know :)). This example grandpa also has a generic answer for what ever else is said to him.  In the example, the player is stored in 'player', and the old man in 'grandpa', and the player said is in 'message'.
  
- To illustrate the setup and use of this plugin, a previously inanimate NPC in Goths Tavern will be modified.  The order of the following steps is not important, but they will take you through every step required to get an NPC that uses the plugin.
+ To illustrate the setup and make use of this plugin, a previously inanimate NPC in Goths Tavern will be modified.  The order of the following steps is not important, but they will take you through every step required to get an NPC that uses the plugin.
  
    * Edit the map file in scorn/taverns/goths as follows.
  
    Index: goths
@@ -75,58 +75,66 @@
    #
    player=Crossfire.WhoIsActivator()
    grandpa=Crossfire.WhoAmI()
    message=Crossfire.WhatIsMessage()
+   
    # Dialog creation:
    speech = Dialog(player, grandpa, "test_grandpa_01")
-   #
+   
    # The first rule is the "hello" answer, so we place it at index 0 of the
-   # rules list. The precondition is that we never said hello before.
-   # The postcondition is to mark "hello" as "1", to remember we already
-   # greeted grandpa.
+   # rules list. The precondition is that we never said hello before. The
+   # postcondition saves a value of "1" into a player file flag named "hello"
+   # so grandpa remembers he has already met this player before.
+   
    prer = [["hello","0"]]
    postr = [["hello", "1"]]
    rmsg = ["Hello, lad!","Hi, young fellow!","Howdy!"]
-   speech.addRule(DialogRule("hello|hi", prer, rmsg, postr),0)
-   #
-   # The second rule is the answer to an hello if we already said it before.
-   # Notice that we used "*" for the postcondition value, meaning that we
-   # are leaving it as it is.
+   speech.addRule(DialogRule(["hello","hi"], prer, rmsg, postr),0)
+   
+   # The second rule is the answer to a greeting if he as already met the player
+   # before.  Notice that "*" is used for the postcondition value, meaning that
+   # the flag will remain set as it was prior to the rule triggering.
+   
    prer = [["hello","1"]]
    postr = [["hello", "*"]]
    rmsg = ["I've heard, you know, I'm not deaf *grmbl*"]
-   speech.addRule(DialogRule("hello|hi", prer, rmsg, postr),1)
-   #
-   # And finally, the generic answer. This is the last rule of the list.
-   # We don't need to match any condition, and we don't need to change them,
+   speech.addRule(DialogRule(["hello","hi"], prer, rmsg, postr),1)
+   
+   # Finally, the generic answer is written. This is the last rule of the list.
+   # We don't need to match any condition, and don't need to change any flags,
    # so we use "*" in both cases this time.
+   
    prer = [["hello","*"]]
    postr = [["hello", "*"]]
    rmsg = ["What ?", "Huh ?", "What do you want ?"]
-   speech.addRule(DialogRule("*", prer, rmsg, postr),2)
-   #
+   speech.addRule(DialogRule(["*"], prer, rmsg, postr),2)
+   
    # We only have to let the old man speak now:
    speech.speak(message)
  
-  * In this example, the player is stored in 'player', and the old man in 'grandpa'. What the player said is in 'message'.
+   * In this example, the player is stored in 'player', and the old man in 'grandpa'. What the player said is in 'message'.
  
-  * Start the crossfire server, login, then enter Goths tavern and walk up to the man now named "grandpa" in the left-hand room.  He is in the top left-hand corner of the room.
+   * Start the crossfire server, login, then enter Goths tavern and walk up to the man now named "grandpa" in the left-hand room.  He is in the top left-hand corner of the room.
  
-  * Say hello two times.
+   * Say hello two times.
  
    Player says: hello
    grandpa says: Hello, lad!
    Player says: hello
    grandpa says: I've heard, you know, I'm not deaf *grmbl*
  
-  * The conversation state is stored in your player file.  For example:
+   * The conversation state is stored in your player file.  For example:
  
    $ grep -ri test_grandpa var
    var/crossfire/players/Player/Player.pl:dialog_test_grandpa_01 hello:1
+ 
+ =====A more complex example=====
+ 
+ A **/python/misc/npc_dialog.py** script has been written that uses CFDialog, but allows the dialog data to be written in a slightly different format.  **/scorn/kar/gork.msg** is an example that uses multiple keywords and multiple precondition values.  Whereas the above example has a linear and predicable conversation paths, note how a conversation with Gork can fork, merge, and loop back on itself.  The example also illustrates how CFDialog can allow dialogs to affect how other NPCs react to a player.  **/scorn/kar/mork.msg** is a completely different dialog, but it is part of a quest that requires the player to interact with both NPCs in a specific way before the quest prize can be obtained.  With the @match system, once the player knew the key words, he could short-circuit the conversation the map designer intended to occur.  CFDialog constrains the player to follow the proper conversation thread to qualify to receive the quest reward.
  
  =====Related Resources=====
  
- *  [[http://crossfire.svn.sourceforge.net/viewvc/crossfire/maps/trunk/python/CFDialog.py?view=log|CFDialog.py]] in SVN.
+   *  [[http://crossfire.svn.sourceforge.net/viewvc/crossfire/maps/trunk/python/CFDialog.py?view=log|CFDialog.py]] in SVN.
  
  ====== Derivative CFDialog Scripts ======
  
  CFDialog Helper Classes provide basic functionality that can be used in scripts.  Some CFDialog derivatives are:
@@ -165,42 +173,46 @@
    {
      "location" : "test_grandpa_01",
      "rules": [
      {
-       "match" : "hello|hi",
+       "match" : ["hello","hi"],
        "pre" : [["hello","0"]],
        "post" : [["hello","1"]],
        "msg" : ["Hello, lad!","Hi, young fellow!","Howdy!"]
      },
      {
-       "match": "hello|hi",
+       "match": ["hello","hi"],
        "pre" :[["hello","1"]],
        "post" :[["hello", "*"]],
        "msg" : ["I've heard, you know, I'm not deaf *grmbl*"]
      },
      {
-       "match" : "*",
+       "match" : ["*"],
        "pre" : [["hello","*"]],
        "post" : [["hello", "*"]],
        "msg" : ["What ?", "Huh ?", "What do you want ?"]
      }
    ]}
  
- **match** is what CFDialog describes as a //keyword//, and corresponds with what the player/character says that the dialog will respond to.
+ For detailed descriptions of the match, pre, post, and msg formats, see the above CFDialog.py documentation.
+ 
+ **match** is a list of keyword strings, and corresponds to what the player says that the dialog will respond to.
+ 
+ In the above example, the first rule is applied if the player/character says "hello" or "hi" and if the "hello" flag is set to "0" (default).  When the rule is applied, the "hello" flag is then set to "1".
  
- **pre** is a list of CFDialog //preconditions// that identifies flags that must be set to a particular value in order to trigger a response if a match is detected.
+ **pre** is a list of preconditions that identifies flags that must be set to a particular value in order to trigger a response if a match is detected.
  
- **post** is a list of CFDialog //postconditions// that specify flags that are to be set if a response is triggered.
+ **post** is a list of postconditions that specify flags that are to be set if a response is triggered.
  
- Above, the first rule is applied if the player/character says ''hello'' or ''hi'' and if the __//hello//__ flag is set to __//0//__ (default).  When the rule is applied, the __//hello//__ flag is then set to __//1//__.
+ All of the rule values are lists, and must be enclosed by square braces, but pre and post are lists of lists, so the double square braces (<nowiki>[[]]</nowiki>) are required.
  
- The double square braces <nowiki>([[]])</nowiki> around **pre** and **post** are required. **pre** and **post** are arrays of arrays. Each item in **pre** and **post** is an array of [variable,value].
+ **msg** defines one or more responses that will be given if the rule triggers.  When more than one "msg" value is set up, the NPC randomly selects which one to say each time the rule is applied.
  
- **msg** defines one or more responses that will be given if the rule triggers.  When more than one **msg** value is set up, the NPC randomly selects which one to say each time the rule is applied.
+ A relatively complex example of an npc_dialog.py dialog is given in the Gork treasure room quest.  See **/scorn/kar/gork.msg** in particular as it demonstrates how multiple precondition flag values may be exploited to produce non-linear and variable-path conversations that are less likely to frustrate a player.  Refer also to **/scorn/kar/mork.msg** to see how more than one dialog can reference the same dialog flags.
  
  ====Related Resources====
  
    * [[http://crossfire.svn.sourceforge.net/viewvc/crossfire/maps/trunk/python/misc/npc_dialog.py?view=log|npc_dialog.py]] in SVN.
    * Some actual in-game dialogs supported by npc_dialog.py are:
      - Mork and Gork mini-quest in Scorn
      - Sigmund in Newbies House
  


IP-Address  : 68.88.122.208
Old Revision: http://wiki.metalforge.net/doku.php/cfdialog?rev=1226633062
New Revision: http://wiki.metalforge.net/doku.php/cfdialog

-- 
This mail was generated by DokuWiki at
http://wiki.metalforge.net/




More information about the crossfire-wiki mailing list