Conversations: Difference between revisions
Lou Montana (talk | contribs) m (→Requirements: link fix) |
Lou Montana (talk | contribs) (Add Arma 3 note about .lip files bug, add FSM description, headers fix) |
||
Line 1: | Line 1: | ||
{{GVI|arma2|1.00}} | {{GVI|arma2|1.00}} | ||
== Introduction == | == Introduction == | ||
Line 10: | Line 11: | ||
* Possibility to create fully dynamic conversations | * Possibility to create fully dynamic conversations | ||
* Transparent syntax (FSM branches allow fast and efficient edits) | * Transparent syntax (FSM branches allow fast and efficient edits) | ||
{{Important| | |||
In '''Arma 3''', using a .lip file for a sound file (.ogg or .wss) creates a glitch making the sound being said about 20× faster. Normal conversations can't be made with [[say]] properly anymore, where this new conversation system will automatically use [[setRandomLip]] during the speech, avoiding the use of a corresponding .lip file.}} | |||
== Requirements == | == Requirements == | ||
'''.bikb''' extension stands for "'''B'''ohemia '''I'''nteractive '''K'''nowledge '''B'''ase" as it was originally used only for storing an AI unit's memory of what it has seen. | '''.bikb''' extension stands for "'''B'''ohemia '''I'''nteractive '''K'''nowledge '''B'''ase" as it was originally used only for storing an AI unit's memory of what it has seen.<br> | ||
This file | This file declares the available sentences in the topic, their sound samples and the corresponding subtitles (see [[#.bikb simple example|example 1]] and [[#.bikb advanced example|example 2]]). | ||
{{Important| | {{Important| | ||
Sounds '''don't''' need to be defined in [[Description.ext#CfgSounds|CfgSounds]] | Sounds '''don't''' need to be defined in [[Description.ext#CfgSounds|CfgSounds]] or [[Description.ext#CfgRadio|CfgRadio]] unless you want to use them with e.g [[playSound]], [[say]] or [[groupRadio]].}} | ||
== Usage == | == Usage == | ||
* a [[#Conversation FSM|Conversation FSM]] will only fire when an AI "receives" a sentence, and react accordingly. | |||
* | * a [[#Conversation Event Handler|Conversation Event Handler]] fire when the player "receives" a sentence, and will also constantly fire ([[onEachFrame]]) as long as the player is pointing at somebody at discussion range. | ||
* | * in the case of a playable unit (can be a player or an AI) both the FSM and the event handler must then be used. | ||
== Commands == | |||
A conversation topic has to be added (''via'' [[kbAddTopic]]) to units for them to be able use it (''via'' [[kbTell]] for example). Once the unit said wanted sentences (''via'' [[kbWasSaid]]), the topic can be removed (''via'' [[kbRemoveTopic]]). | A conversation topic has to be added (''via'' [[kbAddTopic]]) to units for them to be able use it (''via'' [[kbTell]] for example). Once the unit said wanted sentences (''via'' [[kbWasSaid]]), the topic can be removed (''via'' [[kbRemoveTopic]]). | ||
=== Manual conversation example === | === Manual conversation example === | ||
miles [[kbAddTopic]] ["briefing", "kb\briefing.bikb | miles [[kbAddTopic]] ["briefing", "kb\briefing.bikb"]; | ||
shaftoe [[kbAddTopic]] ["briefing", "kb\briefing.bikb | shaftoe [[kbAddTopic]] ["briefing", "kb\briefing.bikb"]; | ||
shaftoe [[kbTell]] [miles, "briefing", "shaftoe_briefing_H_1"]; | shaftoe [[kbTell]] [miles, "briefing", "shaftoe_briefing_H_1"]; | ||
Line 41: | Line 44: | ||
[[hint]] "Conversation ended."; | [[hint]] "Conversation ended."; | ||
{{codecomment|// you could | {{codecomment|// you could - eventually - use [[kbRemoveTopic]] to "clear" the units if the topic is not required anymore. This is not mandatory.}} | ||
== | == Conversation .bikb file == | ||
=== "Interrupted" event === | |||
The left-side conversation menu (with the list of possible sentences) can be closed via backspace at all times. If you want to handle this event as well, you have to add new sentence class called '''Interrupted''' into your .bikb file. It can then be used as a standard _sentenceId in the script. | The left-side conversation menu (with the list of possible sentences) can be closed via backspace at all times. If you want to handle this event as well, you have to add new sentence class called '''Interrupted''' into your .bikb file. It can then be used as a standard _sentenceId in the script. | ||
=== .bikb simple example === | |||
<syntaxhighlight lang="cpp"> | <syntaxhighlight lang="cpp"> | ||
class Sentences | class Sentences | ||
Line 70: | Line 74: | ||
text = $STR_TranslationReference; // has to start with "STR_"! | text = $STR_TranslationReference; // has to start with "STR_"! | ||
speech[] = { "\Sound\bret01.ogg" }; | speech[] = { "\Sound\bret01.ogg" }; | ||
class Arguments {}; | |||
}; | |||
// the Interrupted sentence is triggered when the discussion menu gets closed without answering (e.g using backspace) | |||
class Interrupted | |||
{ | |||
text = "Hey, answer me!"; | |||
speech[] = { "\Sound\interrupted.ogg" }; | |||
class Arguments {}; | class Arguments {}; | ||
}; | }; | ||
Line 82: | Line 94: | ||
=== .bikb advanced example === | |||
See [[Arma_3_Radio_Protocol#Words|Words configuration]] and below for more details. | See [[Arma_3_Radio_Protocol#Words|Words configuration]] and below for more details. | ||
<syntaxhighlight lang="cpp"> | <syntaxhighlight lang="cpp"> | ||
Line 90: | Line 102: | ||
{ | { | ||
text = "%team requesting close air support at grid %location "; | text = "%team requesting close air support at grid %location "; | ||
speech[] = { %Team, RequestingCloseAirSupportAtGrid, %Location }; | speech[] = { %Team, RequestingCloseAirSupportAtGrid, %Location }; // words are defined in Cfg/RadioProtocol/Words | ||
class Arguments | class Arguments | ||
{ | { | ||
Line 104: | Line 116: | ||
startWithConsonant[] = { europe, university }; | startWithConsonant[] = { europe, university }; | ||
</syntaxhighlight> | </syntaxhighlight> | ||
== Conversation FSM == | |||
As stated earlier, the '''Conversation FSM''' fires only when '''an AI''' "receives" a sentence and defines its reaction. | |||
The Conversation FSM receives the following arguments: | |||
* '''_this:''' [[Object]] - receiver or listener of the sentence. One of the units that had this particular script assigned ''via'' [[kbAddTopic]] | |||
* '''_from:''' [[Object]] - the unit that told the sentence | |||
* '''_sentenceId:''' [[String]] - the sentence this unit is reacting to. Defined in .bikb in class Sentences | |||
* '''_topic:''' [[String]] - topic name used in [[kbAddTopic]] | |||
See also: [[FSM]], [[FSM Editor]] | |||
=== Conversation FSM example === | === Conversation FSM example === | ||
{{note|WIP}} | {{note|WIP}} | ||
== Conversation Event Handler == | |||
The Conversation Event Handler is '''not''' an [[:Category:Event_Handlers|Event Handler]] as we know them. | The '''Conversation Event Handler''' is '''not''' an [[:Category:Event_Handlers|Event Handler]] as we know them. | ||
This is a | This is a [[code]] that will be executed with each sentence '''received by a player''' as well as when the player is pointing at a "talkable" person. Following parameters are passed: | ||
* '''_this:''' [[Object]] - | * '''_this:''' [[Object]] - the [[player]] receiving the sentence. Must have had this particular script assigned ''via'' [[kbAddTopic]] | ||
* '''_from:''' [[Object]] - the unit that told the sentence | * '''_from:''' [[Object]] - the unit that told the sentence | ||
* '''_sentenceId:''' [[String]] - the sentence this unit is reacting to. Defined in .bikb in class Sentences | * '''_sentenceId:''' [[String]] - the sentence this unit is reacting to. Defined in .bikb in class Sentences | ||
Line 121: | Line 141: | ||
=== Conversation Event Handler example === | |||
{{codecomment|// here we will be storing all the sentences from which the player will choose (the menu on the left side of the screen) | {{codecomment|// here we will be storing all the sentences from which the player will choose (the menu on the left side of the screen) | ||
// if there is only one option in the array, the sentence will replace the "Talk to" action name}} | // if there is only one option in the array, the sentence will replace the "Talk to" action name}} | ||
BIS_convMenu = []; | |||
{{codecomment|// we want the player to be able to approach his buddy and talk to him via the action menu. | {{codecomment|// we want the player to be able to approach his buddy and talk to him via the action menu. | ||
Line 134: | Line 154: | ||
// then we add that array to BIS_convMenu - the parameters are mostly self-explanatory:}} | // then we add that array to BIS_convMenu - the parameters are mostly self-explanatory:}} | ||
if (_from == buddy1 && _sentenceId == "" && !(_this kbWasSaid [_from, _topic, "hello1", 999999])) then { | [[if]] (_from == buddy1 && _sentenceId == "" && !(_this [[kbWasSaid]] [_from, _topic, "hello1", 999999])) then | ||
{ | |||
BIS_convMenu = BIS_convMenu + [["Say hello.", _topic, "hello1", []]]; | BIS_convMenu = BIS_convMenu + [["Say hello.", _topic, "hello1", []]]; | ||
}; | }; | ||
Line 140: | Line 161: | ||
{{codecomment|// here we make the unit say the proper sentence based on the one he just received | {{codecomment|// here we make the unit say the proper sentence based on the one he just received | ||
// [[switch]]-[[case]]-[[do]] is used here but it is completely up to you how to evaluate it ([[if]]-[[then]] etc.)}} | // [[switch]]-[[case]]-[[do]] is used here but it is completely up to you how to evaluate it ([[if]]-[[then]] etc.)}} | ||
[[switch]] (_sentenceId) [[do]] | |||
{ | { | ||
case "hello1": { | [[case]] "hello1": | ||
_this kbTell [_from, _topic, "hi_how_are_you"] | { | ||
_this [[kbTell]] [_from, _topic, "hi_how_are_you"]; | |||
}; | }; | ||
case "good_you": { | [[case]] "good_you": | ||
_this kbTell [_from, _topic, "fine_thanks"] | { | ||
_this [[kbTell]] [_from, _topic, "fine_thanks"]; | |||
}; | }; | ||
case "what_do_we_do_today": { | [[case]] "what_do_we_do_today": { | ||
{{codecomment|// | {{codecomment|// the player will have 3 answers to choose from:}} | ||
BIS_convMenu = BIS_convMenu + [["Football.", _topic, "choose_football", []]]; | BIS_convMenu = BIS_convMenu + [["Football.", _topic, "choose_football", []]]; | ||
BIS_convMenu = BIS_convMenu + [["Bike.", _topic, "choose_bike", []]]; | BIS_convMenu = BIS_convMenu + [["Bike.", _topic, "choose_bike", []]]; | ||
Line 158: | Line 180: | ||
{{codecomment|// return the sentence list pool}} | {{codecomment|// return the sentence list pool}} | ||
BIS_convMenu | BIS_convMenu; | ||
Revision as of 22:42, 27 March 2018
Introduction
Conversations are a system introduced with Arma 2 and created to enhance discussions. This system allows dynamic conversations and a more fluid sentence/answer flow.
Its main advantages are:
- The system itself waits for the sound sample to finish. No more sample time measuring and countless sleeps!
- Conversation always flows through the appropriate channel (direct for face to face, team radio for distant team members etc.)
- Possibility to create fully dynamic conversations
- Transparent syntax (FSM branches allow fast and efficient edits)
Requirements
.bikb extension stands for "Bohemia Interactive Knowledge Base" as it was originally used only for storing an AI unit's memory of what it has seen.
This file declares the available sentences in the topic, their sound samples and the corresponding subtitles (see example 1 and example 2).
Usage
- a Conversation FSM will only fire when an AI "receives" a sentence, and react accordingly.
- a Conversation Event Handler fire when the player "receives" a sentence, and will also constantly fire (onEachFrame) as long as the player is pointing at somebody at discussion range.
- in the case of a playable unit (can be a player or an AI) both the FSM and the event handler must then be used.
Commands
A conversation topic has to be added (via kbAddTopic) to units for them to be able use it (via kbTell for example). Once the unit said wanted sentences (via kbWasSaid), the topic can be removed (via kbRemoveTopic).
Manual conversation example
miles kbAddTopic ["briefing", "kb\briefing.bikb"]; shaftoe kbAddTopic ["briefing", "kb\briefing.bikb"]; shaftoe kbTell [miles, "briefing", "shaftoe_briefing_H_1"]; waitUntil { shaftoe kbWasSaid [miles, "briefing", "shaftoe_briefing_H_1", 3]; }; miles kbTell [shaftoe, "briefing", "shaftoe_briefing_M_1"]; waitUntil { miles kbWasSaid [shaftoe, "briefing", "shaftoe_briefing_M_1", 3]; }; hint "Conversation ended."; // you could - eventually - use kbRemoveTopic to "clear" the units if the topic is not required anymore. This is not mandatory.
Conversation .bikb file
"Interrupted" event
The left-side conversation menu (with the list of possible sentences) can be closed via backspace at all times. If you want to handle this event as well, you have to add new sentence class called Interrupted into your .bikb file. It can then be used as a standard _sentenceId in the script.
.bikb simple example
class Sentences
{
class example_01
{
text = "Hello Bret."; // sentence subtitle
speech[] = { "\Sound\jemaine01.ogg" }; // sound file path
class Arguments {};
};
class example_02
{
text = "Oh, hello Jemaine.";
speech[] = { "\Sound\bret01.ogg" };
class Arguments {};
};
class lastWord
{
text = $STR_TranslationReference; // has to start with "STR_"!
speech[] = { "\Sound\bret01.ogg" };
class Arguments {};
};
// the Interrupted sentence is triggered when the discussion menu gets closed without answering (e.g using backspace)
class Interrupted
{
text = "Hey, answer me!";
speech[] = { "\Sound\interrupted.ogg" };
class Arguments {};
};
};
// Don't worry about these.
class Arguments {};
class Special {};
startWithVocal[] = { hour };
startWithConsonant[] = { europe, university };
.bikb advanced example
See Words configuration and below for more details.
class Sentences
{
class AirstrikeRequest
{
text = "%team requesting close air support at grid %location ";
speech[] = { %Team, RequestingCloseAirSupportAtGrid, %Location }; // words are defined in Cfg/RadioProtocol/Words
class Arguments
{
class Team { type = "simple"; };
class Location { type = "simple"; };
};
};
};
class Arguments {};
class Special {};
startWithVocal[] = { hour };
startWithConsonant[] = { europe, university };
Conversation FSM
As stated earlier, the Conversation FSM fires only when an AI "receives" a sentence and defines its reaction. The Conversation FSM receives the following arguments:
- _this: Object - receiver or listener of the sentence. One of the units that had this particular script assigned via kbAddTopic
- _from: Object - the unit that told the sentence
- _sentenceId: String - the sentence this unit is reacting to. Defined in .bikb in class Sentences
- _topic: String - topic name used in kbAddTopic
See also: FSM, FSM Editor
Conversation FSM example
Conversation Event Handler
The Conversation Event Handler is not an Event Handler as we know them. This is a code that will be executed with each sentence received by a player as well as when the player is pointing at a "talkable" person. Following parameters are passed:
- _this: Object - the player receiving the sentence. Must have had this particular script assigned via kbAddTopic
- _from: Object - the unit that told the sentence
- _sentenceId: String - the sentence this unit is reacting to. Defined in .bikb in class Sentences
- _topic: String - topic name used in kbAddTopic
Conversation Event Handler example
// here we will be storing all the sentences from which the player will choose (the menu on the left side of the screen) // if there is only one option in the array, the sentence will replace the "Talk to" action name BIS_convMenu = []; // we want the player to be able to approach his buddy and talk to him via the action menu. // we need to check: // if the player is pointing at his buddy // if the player is not answering any of his buddy's sentences // if the player hasn't told him hello already // then we add that array to BIS_convMenu - the parameters are mostly self-explanatory: if (_from == buddy1 && _sentenceId == "" && !(_this kbWasSaid [_from, _topic, "hello1", 999999])) then { BIS_convMenu = BIS_convMenu + [["Say hello.", _topic, "hello1", []]]; }; // here we make the unit say the proper sentence based on the one he just received // switch-case-do is used here but it is completely up to you how to evaluate it (if-then etc.) switch (_sentenceId) do { case "hello1": { _this kbTell [_from, _topic, "hi_how_are_you"]; }; case "good_you": { _this kbTell [_from, _topic, "fine_thanks"]; }; case "what_do_we_do_today": { // the player will have 3 answers to choose from: BIS_convMenu = BIS_convMenu + [["Football.", _topic, "choose_football", []]]; BIS_convMenu = BIS_convMenu + [["Bike.", _topic, "choose_bike", []]]; BIS_convMenu = BIS_convMenu + [["Arma II.", _topic, "choose_arma2", []]] }; }; // return the sentence list pool BIS_convMenu;