Response System

From Valve Developer Community

(Redirected from Response rules)
Jump to: navigation, search

The Response Rules system is used by NPCs to decide what line of speech, and/or animation, they should use when they want to say something. NPCs attempt to speak in response to a variety of events in the game. Their speech attempts are fired either by the AI code, or by mapmaker inputs. In both cases, the speech attempt does not specify a line of speech to use, it just specifies a speech concept. This concept is passed into the Response Rules system, along with a set of response data that describes the current state of the world. The Response Rules system determines the most appropriate line of speech to use for the concept & data passed in, and returns a response (usually in the form of a .VCD) which the NPC then plays.

Contents

Purpose

The purpose of the Response Rules system is to make it easy for you to add context-specific speech to the game. It allows you to easily add new speech to the game without having to write code, or modify a .BSP, and yet still have complete control over how & when that speech will be used. It's best used for speech that comes out of the AI system, since those lines will be spoken many times throughout a game. (e.g. Citizens say something when they reload their weapon. A lot of citizens will reload their weapons during the course of the game.)

Among other things, the Response Rules system allows you to:

  • Control the re-use behavior of individual lines of speech:
e.g. Don't repeat this line for X seconds, Don't repeat until all other similar lines have been used, or Never repeat.
  • Control the speech selection process:
e.g. When a citizen shoots at his enemy, he might want to declare his intentions with some speech. He could:
  • Choose a line based on his current weapon: "Eat shotgun!", "My RPG can handle this!", or "A .357 round should do the trick!"
  • Choose a line based on the type of enemy he's attacking: "I hate headcrabs!", "Take this, you Combine bastards!", or "This pistol is damn near useless against that antlion guard!"
  • Choose a line based on the distance to his enemy: "Can't miss somethin' this close!", or "Get over here so I can shoot you!"
  • Choose a line that's any combination of the above: "My SMG isn't much use at this range!", or "These Combine soldiers love my shotgun!"
  • Add almost any other kind of criteria you might care about, and choose lines based them.
e.g. You might want an NPC to use a different line if the player has moved a cup that was sitting on a table in front of the NPC.

Structure

The Response Rules system is made up of five core pieces: Concepts, Response Data, Criteria, Rules, and Response Groups. The way these are used is as follows:

  1. An NPC requests a line of speech for a speech concept
    • For example, let's say our NPC requests a line of speech for the TLK_SHOT concept. An NPC speaks this concept whenever they're shot by an enemy.
  2. The NPC generates a chunk of response data reflecting his current state, and other relevant data about the state of the world.
    • So when our NPC requests a line for the TLK_SHOT concept, he would also pass in this data. Among other things, it might contain the type of the enemy that shot him, the distance to his enemy, his current health, and so on.
  3. The concept and response data are passed into the Response Rules system.
  4. The Response Rules system has a big list of rules
    • Each rule contains a list of criterion, each of which tests the value of something in the response data passed in by the NPC.
    • Each rule gets a score based upon how many of the criteria are true.
      • So, in our NPC-being-shot example, there might be a couple of rules used to decide which line to speak. One rule might contain criteria that test to see if our NPC is very close to the enemy who shot him. Another rule might test to see if it was a specific type of enemy that shot him (such as a Combine Soldier). Another rule might test to see if our NPC is nearly dead after the shot (perhaps <25% of his health is left).
  5. The Response Rules system scores all of the rules in its list, and chooses the one that scores highest.
  6. The rule that scores the highest is chosen, and it then specifies a response group.
  7. A response group is simply a list of possible responses, each of which might be a line of speech and/or animation. One response is randomly chosen from the list, and is then given back to the NPC to play.
    • In our example, a response group for the rule that checks to see if our NPC's health is <25% might have several ways of responding to TLK_SHOT. For example, the group might contain a list of lines like these: "One more shot like that, and I'm done for!", "Oh man, I'm in trouble!", and "I need medical attention over here!"
    • Or perhaps the rule that checks the type of enemy could point to response groups that have custom lines depending on the enemy type. For example, a rule could check for the enemy type being a combine soldier, and point to a response group with these lines in it: "That combine soldier's got me pinned down!", and "Help me with this soldier!". Another rule could check for the enemy being a combine gunship, and point to a group with: "That gunship is kicking my butt!" and "Someone help me take down that gunship before it kills me!"
  8. If no rule matches the response data, or the chosen response group doesn't have any responses left, the NPC doesn't say anything.

Concepts

A concept is a string that represents the high-level reason for the NPC's speech attempt. There are a set of concepts defined inside the AI code which will be called automatically by NPCs, but you can also freely create your own and invoke them with each actor's speakresponseconcept input.

Some of the predefined AI concepts are:

TLK_HELLO		When I first meet the player.
TLK_IDLE		When I have been idle for a while.
TLK_USE		When the player tries to +USE me.
TLK_PLPUSH		When the player pushes me away.
TLK_STARE		When the player stares at me for a while.
TLK_DANGER		When I see something nearby that's dangerous (e.g. a grenade).
TLK_WOUND		When I've taken damage.
TLK_HIDEANDRELOAD	When I decide to hide and reload my gun.
TLK_PLYR_PHYSATK	When I've been hit by an object thrown by the player.

Not all NPCs speak all concepts, and not all NPCs speak concepts under the same circumstances. See list of response concepts for a full list.

Response data

Response data is created and passed into the Response Rules system whenever a speech attempt is made. It is a set of KeyValues that reflect the state of the NPC that's attempting to speak. Here is an example response data set created by Alyx, who's trying to speak because she just killed her current enemy:

concept                = TLK_ENEMY_DEAD          The concept the NPC is trying to speak.
map                    = d3_c17_07               The name of the current .BSP.
classname              = npc_alyx                The classname of the speaking NPC.
name                   = alyx                    The targetname of the speaking NPC .
health                 = 80                      The health of the speaking NPC.
healthfrac             = 1.000                   The health of the speaking NPC, as a fraction of the NPC's max.
skill.cfg              = 1                       The current skill level.
timesinceseenplayer    = 0.090000                The amount of time since the speaking NPC has seen the player.
distancetoenemy        = 312.639679              The distance from the speaking NPC to its current enemy.
activity               = ACT_RUN                 The animation activity the speaking NPC is running.
npcstate               = [NPCState::Combat]      The AI state of the speaking NPC.
enemy                  = npc_combine_s           The classname of the speaking NPC's current enemy.
speed                  = 79.235                  The movement speed of the speaking NPC.
weapon                 = weapon_alyxgun          The current weapon being held by the speaking NPC.
distancetoplayer       = 211.240692              The distance from the speaking NPC to the player.
seeplayer              = 1                       Whether or not the speaking NPC can see the player.
seenbyplayer           = 0                       Whether or not the speaking NPC is within the player's view.
readiness              = agitated                The readiness level of the speaking NPC.
playerhealth           = 100                     The player's current health.
playerhealthfrac       = 1.000                   The player's current health, as a fraction of the player's max.
playerweapon           = weapon_shotgun          The current weapon being held by the player.
playeractivity         = ACT_WALK                The animation activity the player is running.
playerspeed            = 0.000                   The movement speed of the player.

All of these pieces of data can be checked by criteria, and used to make decisions about which response group to use for the desired concept. For instance:

  • The enemy key could be used to pick the right response to the TLK_ENEMY_DEAD concept. Instead of making a general statement, Alyx could say "I took care of that soldier!" or "I took care of that headcrab!".
  • The healthfrac field could be used to choose a "Phew, that was close!" line if her health was <20% when she finished off her enemy.
  • The distancetoenemy field could be used to choose different lines for when she killed her enemy at long or short range. i.e. "Those guys are scary when they get that close!" or "It's not easy hitting 'em at that range."

The keys inside the response data will vary for different NPC types, and for different world states (i.e. NPCs that aren't in combat won't have enemy or distancetoenemy keys). Additionally, mapmakers can append extra data to specific NPCs, or to all NPCs in the game. See #Advanced Response Rules Usage for more info.

Criteria

A criterion is a single check against a key & value inside the response data. When a rule is scored, each criterion is checked against the response data, and the rule receives points for its criteria that successfully match. The amount of points a criterion earns for the rule is determined by the criterion's weight. Criteria are defined inside the Response Rules Script Files (see below). The following format is used:

criterion <criterion name> <key to check> <desired value> <optional: weight X> <optional: required>

The parameters are as follows:

criterion name
The name of the criterion. Must not match an existing criterion.
key to check
The key within the response data that this criterion will check.
desired value
The desired value of the key within the response data. This can take multiple forms:
  • Numeric values: "0", "1", or "100".
  • Inverse Numeric values: "!=0" would match if the value is not equal to 0.
  • String value: "npc_alyx", "weapon_alyxgun", or "npc_combine_s".
  • Enumerated value: "[NPCState::Combat]".
  • Ranges:
    • ">0" : Match if the value is greater than 0.
    • "<=0.5" : Match if the value is less than, or equal to, 0.5.
    • ">10,<=50" : Match if the value is greater than 10 and less than, or equal to, 50.
    • ">0,<[NPCState::Alert] : Match if the value is greater than 0 and less then the value of enumeration for NPCState::Alert.
weight X
An optional parameter, where X is the amount of points this criterion is worth if it matches. If unspecified, criterion are worth 1 point by default.
required
An optional parameter that states that this criterion is required for rules containing it to be used at all. If a required criterion does not match successfully, rules containing it score 0 and are immediately passed over.

Some examples (from the base criterion list in the Response Rules Script File):

  • This defines a criterion named PlayerNear, which checks to make sure the player is within 500 units of the speaking NPC.
criterion "PlayerNear" "distancetoplayer" "<500" required
  • This defines a criterion named IsCitizen, which checks to make sure the speaking NPC is a citizen.
criterion "IsCitizen" "classname" "npc_citizen" "required"
  • This defines a criterion named IsMap_d3_c17_12, which checks to make sure the game is currently on d3_c17_12.bsp. Useful for making all the citizens in one map say different lines than other maps.
criterion "IsMap_d3_c17_12" "map" "d3_c17_12" "required"
  • This defines a criterion named IsBob, which checks to make sure the speaking NPC has a targetname of "bob". This is a unique citizen in the game, and this criteria makes it easy to have him say unique lines.
criterion "IsBob" "targetname" "bob" required

Rules

A rule contains a criteria list and a response group. The rule receives points for each of the criteria that successfully matches the response data. The response group contained by the highest scoring rule is used to determine the exact speech the NPC will use. Rules are defined inside the Response Rules Script Files (see below). The following format is used:

rule <rule name>
{
   criteria <criterion name 1> [optional: <criterion name 2> <criterion name 3> etc.]
   response <response group name> [optional: <response group name 2> etc.]
   [optional: matchonce]					
}

The parameters are as follows:

  • rule name : The name of the rule. Must not match an existing rule.
  • criterion name X : The name of criterion defined in the script files.
  • response group name : The name of a response group that should be chosen if this rule scores the highest.
  • matchonce : An optional parameter which, if specified, causes this rule to be deactivated once it has been chosen.

For example, this defines a rule called CitizenTalkStare. ConceptTalkStare is a criterion that checks to make sure the concept the speaking NPC wants to speak is "TLK_STARE". IsCitizen is a criterion that checks to make sure the speaking NPC is a citizen. NPCIdle is a criterion that checks to make sure the NPC's state is "NPCState::Idle". If this rule scores highest, the response group that will be used is CitizenTalkStare.

rule CitizenTalkStare
{
   criteria     ConceptTalkStare IsCitizen NPCIdle
   response     CitizenTalkStare
}

Note that the rule name and the response group name can be identical because rule names need only be unique amongst rules, and response groups names only unique amongst groups.

Response groups

A Response group contains a set of possible responses, along with some optional data that defines how the responses should be used. When a response group is chosen by a rule rule, a response is chosen from the list and given back to the speaking NPC to use. Response Groups are defined inside the Response Rules Script Files (see below). The following format is used:

response <responsegroupname>
{
   [optional: permitrepeats]
   [optional: sequential]	  
   [optional: norepeat]		  

   <response type> <response parameter> <optional: [nodelay | defaultdelay | delay X ] [weapondelay X] [speakonce] [odds X] [respeakdelay X] [soundlevel "SNDLVL_xxx"] [displayfirst] [displaylast] [weight X]>
   <response type> <response parameter> <optional: [nodelay | defaultdelay | delay X ] [weapondelay X] [speakonce] [odds X] [respeakdelay X] [soundlevel "SNDLVL_xxx"] [displayfirst] [displaylast] [weight X]>
   <response type> <response parameter> <optional: [nodelay | defaultdelay | delay X ] [weapondelay X] [speakonce] [odds X] [respeakdelay X] [soundlevel "SNDLVL_xxx"] [displayfirst] [displaylast] [weight X]>
   etc
}

The response group parameters are as follows:

  • permitrepeats : If specified, it allows responses in this group to repeat. If unspecified, the default behavior is to use all responses in the list before repeating any,
  • sequential : If specified, responses will be used in the order they're listed in the group. If unspecified, the default behavior is to randomly choose responses from the list.
  • norepeat : If specified, once all responses in the list have been played, the response group will be disabled. Any rules that choose this response group will return no response to the speaking NPC.

The response group then lists as many responses as desired, with each response listed using the following parameters:

  • response type : The type of the response. Must be one of:
    • "speak" : The response is an entry in sounds.txt. See Soundscripts.
    • "sentence" : The response is a sentence name from sentences.txt.
    • "scene" : The response is a .vcd file. See Choreography Implementation for more information.
    • "response" : The response is a reference to another response group.
    • "print" : The response is some text that should be printed to console in developer 2 (used for placeholder responses).
  • response parameter : The appropriate data for the response type. i.e. if the response type is "scene", this is the .vcd file. If the response type is "speak", this is the name of the sounds.txt entry.
  • Optional post-response delay parameters:
    • nodelay : After the response has finished, the NPC is allowed to speak again immediately.
    • defaultdelay : After the response has finished, the NPC won't be allowed to speak for a random amount, between 2.8 & 3.2 seconds.
    • delay X : After the response has finished, the NPC won't be allowed to speak for X seconds. X can also be a range, specified in the following format: "<min delay>,<max_delay>". i.e. "5.5,7.5"
  • weapondelay X : When the response starts, a player ally will not fire their weapon for X seconds.
  • speakonce : Don't use this response more than once.
  • odds X : If specified, then when this response is chosen, there is a chance the NPC will say nothing instead of saying the response. The chance of saying nothing is (100 - X)%.
  • respeakdelay : If specified, this response may not be used again for X seconds. X can also be a range, specified in the following format: "<min delay>,<max_delay>". i.e. "5.5,7.5"
  • soundlevel : If specified, this soundlevel should be used for the response instead of the default SNDLVL_TALKING.
  • displayfirst : If specified, this response should be used first (ignores the weight parameter).
  • displaylast : If specified, this response should be used last (ignores the weight parameter).
  • weight : If specified, used to weight the selection of the responses in the list. By default, all responses have a weight of 1.

For example, the following response group is used by citizens to respond to the TLK_STARE concept. Citizens will use the responses in the list in the order they're listed (due to the sequential parameter). Each response, when chosen, stops the NPC from talking for a random amount of time between 10 & 20 seconds.

response "CitizenTalkStare"
{
   sequential
   scene "scenes/npc/$gender01/doingsomething.vcd" delay "10,20"
   scene "scenes/npc/$gender01/getgoingsoon.vcd"  delay "10,20"
   scene "scenes/npc/$gender01/waitingsomebody.vcd"  delay "10,20"
}

Script files

The /scripts/talker/response_rules.txt is the base script file that contains all the criteria, rules, and response groups used by the Response Rules System. The file can also include other files using the #include keyword, which allows you to cleanly divide the rules up according to NPC, map, and so on. Note that some entities, like the env_speaker, specify their own script files that contain a subset of the criteria, rules, and response groups for the entity to use. See scripts/talker/terminal_pa.txt for an example used by the terminal announcement at the train station.

Advanced response rules usage

There are several powerful ways that the ResponseContext keyfield and the AddContext input can be used to make NPCs more responsive to the changing state of the world they're in. Both the ResponseContext keyfield and the AddContext input take a string parameter, in the following format: key:value;key:value;key:value;...

It can be used as follows:

Firing custom response events with speakresponseconcept
Absolutely anything can be passed to an NPC as a response concept, so long as it is to be found somewhere in the script files. You aren't limited to the AI's predefined TLK_* concepts at all.
For example, you might want NPCs from a onlooking group to speak congratulatory response concepts when a player successfully solves part of a puzzle.
Setting custom KeyValues on an NPC via the ResponseContext keyfield
The ResponseContext keyfield is a field inside all NPCs that allows you to set arbitrary KeyValues that will be passed in to the Response Rules system whenever that NPC requests lines. he KeyValues that you set will be appended to the Response Data passed into the Response Rules.
For example, you may have a single citizen who you want to have a custom way of saying Hello! to the player. You could set that citizen's ResponseContext keyfield to custom_hello_guy:1, and then define a new criteria that checks to see if the custom_hello_guy key is set to 1. Then you would make a new rule for the TLK_HELLO concept that also contains your new criteria, and this rule would score higher when the custom guy tries to speak TLK_HELLO.
Firing the AddContext input on NPCs
The AddContext input on an NPC allows you to dynamically set arbitrary KeyValues that will be passed in to the Response Rules system whenever that NPC requests lines. The KeyValues that you set will be appended to the Response Data passed into the Response Rules.
For example, you might want a Citizen to say something differently if the player has moved a cup sitting on a nearby table. You would connect the OnPhysGunPickup output of the cup to the AddContext input on the Citizen, with a parameter of something like player_pickedup_cup:1. Then you could define a new criteria that checks to see if the player_pickedup_cup key is set to 1, and use that criteria in a rule that chooses an appropriate line.
Firing the AddContext input on the World
If you fire the AddContext input on the worldspawn entity, the KeyValues you specify will be passed into the Response Rules system everytime any NPC requests lines on that map. This makes the worldspawn entity a valuable storage place for data that all NPCs on the map should use when choosing lines.
For example, you might want all the Citizens in a town to choose different lines if the mayor has died. You would connect the OnDeath output of the mayor NPC to the AddContext input of the worldspawn entity, with a parameter of something like mayor_is_dead:1. Then you could define a new criteria that checks that the mayor_is_dead key is set to 1, and have Citizen rules that use it to choose different lines after the mayor has died.
Firing the AddContext input on the player
If you fire the AddContext input on the player entity (using the !player targetname), the keyvalues will be passed to the Response system every time any NPC requests lines. In addition, these KVs will persist over level transitions, just like the player. This makes the player entity a valuable storage place for data that NPCs in later maps should use when choosing lines.
Note:The word player will be prefixed to every key passed to !player.
For example, you might want a Citizen to say something differently if the player killed a certain combine soldier in a previous map. You would connect the OnDeath output of the Combine Soldier to the AddContext input of the player entity, with a parameter of something like that_soldier_dead:1. Then you could define a new criteria that checks the playerthat_soldier_dead key is set to 1, and have Citizen rules that use it to choose different lines. The playerthat_soldier_dead key would be set to 1 for all NPCs that speak throughout the rest of the game.
Changing existing KeyValues in the Response Data
If you fire the AddContext input on an entity, and pass in a Key name that already has a Value in that entity, it'll simply overwrite the Value for the Key.

Debugging

To do: sv_debugresponses

Notes

  • To be able to use the Response Rules system, an NPC must be derived from the CAI_BaseActor class.
  • See the scripts/talker/npc_*.txt files for examples of specific NPC response rules.
  • The scripts/talker/response_rules.txt is the manifest for the response rules system. If you add new response rule script files for your new NPC, make sure you #include it at the end of the scripts/talker/response_rules.txt file.

See also

Personal tools
Namespaces
Variants
Actions