Jump to content
HateDread

Using Dialogue System - Between Player and AI?

Recommended Posts

Howdy all,

I've been reading up, in the thread at http://forums.bistudio.com/showthread.php?t=91875, but I can't seem to get it to work/understand it, even upon review of both the kbtell and kbWasSaid biki entries.

I'm wondering, if I want a simple conversation between the player, and an AI character, in an SP mission, do I need to use FSMs? (Not clear in the aforementioned thread).

How do I setup this simple conversation (I realise it's not exactly 'simple'). I.e. the player approaches the AI, after being called over:

Player = Red

AI = Blue

----

Uhh... yeah?

They got you too, eh?

Yeah, something like that.

Etc...

And, within such a system, how does one add multiple conversation trees? The linked thread doesn't really make it clear, nor does the example, even with comments:

// we need to check:

// if I'm pointing at my buddy

// if I'm not answering any of his sentences

// if I haven'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

// I use switch-case-do, it's 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": {

// here the player will have 3 answers to choose from

BIS_convMenu = BIS_convMenu + [["Football.", _topic, "choose_footbal", []]];

BIS_convMenu = BIS_convMenu + [["Bike.", _topic, "choose_bike", []]];

BIS_convMenu = BIS_convMenu + [["Arma II.", _topic, "choose_arma2", []]]

};

};

// return the sentence list pool

BIS_convMenu

Any help would be MUCH appreciated!

EDIT: Since learning how to achieve the above (thanks to the help of Evil_Echo), I have written a guide to conversations, FSMs, etc. Part one is available here, and part two, here. Make sure to read the fine print!

Regards,

- HateDread.

Edited by HateDread

Share this post


Link to post
Share on other sites

never really used the conversation system but i know that if you download the bitools kit it has a fsm viewer that is really helpful,id never used it and was using notepad for fsm's and it made no sense to me lol,glad i got it tho.sorry i couldnt help more

Share this post


Link to post
Share on other sites

The FSM editor is pretty much required for manipulating FSM files, plain text editor just does not cut it there.

For conversations, you need a couple of files.

The bikb file, contains the text phrases to utter or references to stringtables entries, and references to optional sound files if you want audio. You include all dialog for all parties of a conversation here. You can have multiple files for different topics and they can be used simultaneously if you want.

For automated responses you need one or two files each character in the conversation. A FSM file drives the responses for AI and a sqf script for when that character is currently run by a player. The logic in those files is just simple action-response events ( if someone says this then I say/do that ), so if you look at the sqf version you can figure out what the FSM would be and vice-versa. For non-automated dialog, there is no need for entries in those files at all, so in some cases you may not even need more than the bikb file.

All the files go in a kb\ folder in your mission...

briefing.bikb

briefing_Alpha.fsm

briefing_Alpha.sqf

briefing_Delta.fsm

briefing_Delta.sqf

evac.bikb

evac_Alpha.fsm

evac_Alpha.sqf

evac_Delta.fsm

evac_Delta.sqf

evac_HotShot.fsm

evac_McKay.fsm

evac_McKay.sqf

launch.bikb

launch_Delta.fsm

launch_Delta.sqf

launch_Patriot.fsm

launch_Patriot.sqf

repair.bikb

repair_Alpha.fsm

repair_Alpha.sqf

repair_Delta.fsm

repair_Delta.sqf

repair_Konstantine.fsm

For evac conversations, here is the bikb...

class Sentences {
class M1_0 {
	text = $STR_DIALOG_EVAC_M1_0;
	speech[] = {};
	class Arguments {};
};
class D1_0 {
	text = $STR_DIALOG_EVAC_D1_0;
	speech[] = {};
	class Arguments {};
};
class M1_1 {
	text = $STR_DIALOG_EVAC_M1_1;
	speech[] = {};
	class Arguments {};
};
class D1_1 {
	text = $STR_DIALOG_EVAC_D1_1;
	speech[] = {};
	class Arguments {};
};
class M1_2 {
	text = $STR_DIALOG_EVAC_M1_2;
	speech[] = {};
	class Arguments {};
};
class D1_2 {
	text = $STR_DIALOG_EVAC_D1_2;
	speech[] = {};
	class Arguments {};
};
class D1_3 {
	text = $STR_DIALOG_EVAC_D1_3;
	speech[] = {};
	class Arguments {};
};
class D1_4 {
	text = $STR_DIALOG_EVAC_D1_4;
	speech[] = {};
	class Arguments {};
};
class D1_5 {
	text = $STR_DIALOG_EVAC_D1_5;
	speech[] = {};
	class Arguments {};
};
class D1_6 {
	text = $STR_DIALOG_EVAC_D1_6;
	speech[] = {};
	class Arguments {};
};
class M1_3 {
	text = $STR_DIALOG_EVAC_M1_3;
	speech[] = {};
	class Arguments {};
};
class M1_4 {
	text = $STR_DIALOG_EVAC_M1_4;
	speech[] = {};
	class Arguments {};
};
class H1_0 {
	text = $STR_DIALOG_EVAC_H1_0;
	speech[] = {};
	class Arguments {};
};
class A1_0 {
	text = $STR_DIALOG_EVAC_A1_0;
	speech[] = {};
	class Arguments {};
};
class H1_1 {
	text = $STR_DIALOG_EVAC_H1_1;
	speech[] = {};
	class Arguments {};
};
class A1_1 {
	text = $STR_DIALOG_EVAC_A1_1;
	speech[] = {};
	class Arguments {};
};
class H1_2 {
	text = $STR_DIALOG_EVAC_H1_2;
	speech[] = {};
	class Arguments {};
};
class H1_3 {
	text = $STR_DIALOG_EVAC_H1_3;
	speech[] = {};
	class Arguments {};
};
class H1_4 {
	text = $STR_DIALOG_EVAC_H1_4;
	speech[] = {};
	class Arguments {};
};
class H1_5 {
	text = $STR_DIALOG_EVAC_H1_5;
	speech[] = {};
	class Arguments {};
};
class H1_6 {
	text = $STR_DIALOG_EVAC_H1_6;
	speech[] = {};
	class Arguments {};
};
class NukeCity {
	text = $STR_DIALOG_LAUNCH_HQW_City_Nuked;
	speech[]={};
	class Arguments {
		class Burst_type {type = "simple";};
		class Grid {type = "simple";};
		class Location {type = "simple";};
	};
};
class NukeLocation {
	text = $STR_DIALOG_LAUNCH_HQW_Location_Nuked;
	speech[]={};
	class Arguments {
		class Burst_type {type = "simple";};
		class Grid {type = "simple";};
	};
};
class Interrupted {
	text = "";
	speech[] = {""};
	class Arguments {};
};
};
class Arguments{};
class Special{};
startWithVocal[] = {hour};
startWithConsonant[] = {europe, university};

and script file for Delta Team, the base commander....

BIS_convMenu = [];

switch (_sentenceId) do {
case "M1_0": {
	_this kbTell [_from, _topic, "D1_0"];
};

case "M1_2": {
	_this kbTell [HotShot, _topic, "D1_2"];
};

case "H1_3": {
	_this kbTell [_from, _topic, "D1_3"];
};

default {
};
};

// return the sentence list pool
BIS_convMenu

Share this post


Link to post
Share on other sites

Okay, so;

- In the event that I want a dialogue tree (in my SP RPG mission), between the player and AI, with the player's conversation options being manually-chosen (i.e. the scroll menu), and the AI then auto-responding to each one accordingly, then returning to the root conversation menu (like how it's done in Oblivion/Fallout3 - there are 'subjects' the player can talk about, each with their own AI responses and options), how would I do so?

-How/why use a stringtable for your responses/dialogue? And;

- I am still unsure if in my above example I need an FSM or not. I don't understand that part.

Thank you for your help!

Share this post


Link to post
Share on other sites

- stringtables provide 2 benefits (and maybe more). One is that you can provide all in-game text in multiple languages. Of course you would need to translate it yourself, but the game engine will automatically pick the right language for you if it's available. The other advantage is that all of your text is in one place, so it's easy to find and modify.

- You need the full FSM if you are going to do interactive dialog, like in Fallout3. I personally am using just the bikb files (for the class definitions, as Evil_Echo shows above), and the companion SQF which calls the classes in the bikb with kbTell and kbWasSaid. I like that it handles things like whether to use the radio or direct conversation automatically, and it lets one person finish speaking before the next one talks.

Basically, if you just want a certain dialog spoken in a linear fashion, no FSM required. If you want choices, you need the FSM. Hope it helps :)

Share this post


Link to post
Share on other sites

When I went through the BIS missions in the FSM editor, it looked as though all the .fsm files regarding speech were automatically generated. They're hiding something from us. :(

Edited by bhaz

Share this post


Link to post
Share on other sites

Thanks for your help so far, guys!

Alright, so what I don't understand is what Evil said, in an sqf file:

BIS_convMenu = [];

switch (_sentenceId) do {

case "M1_0": {

_this kbTell [_from, _topic, "D1_0"];

};

case "M1_2": {

_this kbTell [HotShot, _topic, "D1_2"];

};

case "H1_3": {

_this kbTell [_from, _topic, "D1_3"];

};

default {

};

};

// return the sentence list pool

BIS_convMenu

I understand the -idea- of switch, but not how it's being used here.

- Also, I have no idea of FSMs. Are there any basic examples with lots of comments?

- What are the advantages of using this over, say, 'Globalchat, etc, with addactions to cue responses?'

- And, finally, how do I actually make/use the string-table?

Sorry for asking so much.

Cheers,

- HateDread.

Share this post


Link to post
Share on other sites

I use a switch vs a series of if-then-elses to make the code cleaner.

I use tests at all because that is how you get a character to automatically respond to what another has said ( this is AI after all ).

The advantage is - you don't have to write a long series of chat statements. Just the first one to trigger the conversation and the responses and counter-responses just flow. No need to time the sound samples and add sleeps to ensure that A is done talking before B starts up. Also the system picks the right channel for you, local if close by, radio if distant, vehicle if both in same ride....

Stringtables - just a handy way to package up phrases. And as already mentioned you can have phrases in different languages all keyed to one tag - game makes the substitutions for you auto-magically.

The string table can be a file in one of two formats. The older way is a .csv file, comma separated values - a common format supported by spreadsheets like Excel. Kinda clunky and harder to edit. The new way is in XML, much cleaner and even viewable by most web browsers. Only downside at the moment is the BI wiki has not documented the XML version yet.

:smiley-grimmace:

It's not hard though. Block and tag in a manner similar to html...

<?xml version="1.0" encoding="UTF-8"?>
<Project name="Arma2">
<Package name="Mission">
<Container name="Red Dawn">
<Key ID="STR_DIALOG_BRIEFING_D1_0">
<English>Hammer 1 - attend the morning briefing.</English>
</Key>
<Key ID="STR_DIALOG_BRIEFING_D1_1">
<English>We'd appreciate you joining us at the briefing, soldier.</English>
</Key>
<Key ID="STR_DIALOG_BRIEFING_D1_2">
<English>Hammer 1 - get your butt in a chair at the briefing tent now!!!</English>
</Key>
...
</Container>
</Package>
</Project>

The tags used for each "Key ID" are what are referenced in the bikb file.

Share this post


Link to post
Share on other sites

I think I get the switch, but once you get a received sentence (i.e. the one said in reaction to this: _this kbTell [_from, _topic, "D1_0"];, how do you continue down this dialogue path without returning to the start? (May not make sense - it's 3 am). I still don't understand how this system works... how do you dictate flow?

For example; I want JohnRayner to say "You up for the task, or not?", followed by player choices of "Yes", and "No", with yes leading to further branches like him responding "Good, --info here--", then the player can ask questions about it, whilst the "No" leads to him replying "Fine", and the player having to restart conversation (Maybe with different start - i.e. "Hey, about that task...", then he responds "Oh, you're actually interested now, eh?" and on from there. Does that make sense? (I hope so :/ )

I don't quite understand your second line. 'Tests'?

Ahhh, so you recommend the .xmls, then? (Like choosing .sqf over .sqs?) What is the first character(s) in your quote? Looks foreign/unreadable. Apart from that, it seems to make sense, in that part, at least. And, as I started to create one in line with your example, I am wondering, what is the recommended format/syntax for naming them, for organisational purposes? (I.e. where you have STR_DIALOG_BRIEFING_D1_1, and STR_DIALOG_BRIEFING_D1_2, etc; what/why the 'D1_1','D1_2', etc).

I feel really dirty for this, but I had spare time, so using the script here, I made a small dialogue option, in .sqf only (without sounds). It might look better copied to notepad. It starts as amateur 'globalradio' commands at first, then ends convo after player accepts the offer. Please note it's 3am and this script is dirty. You can only read it in the bath, or in a shower. Good luck.

JohnRayner globalchat "Hey!";
	Sleep 3;
Player globalchat "Uhh, hi.";
	Sleep 2;
JohnRayner globalchat "So those bastards came after you too, eh?";
	Sleep 2.5;
Player globalchat "I... I think so.";
	Sleep 1.5;
JohnRayner globalchat "You 'think so'?";
	Sleep 1.5;
JohnRayner globalchat "Well, listen here, boy - they only just passed through.";
	Sleep 2.5;
JohnRayner globalchat "They shot, burnt and pillaged all they could.";
	Sleep 2;
JohnRayner globalchat "The ones you saw were just a scouting party. The full force, oh, it was much worse.";
	Sleep 3;
JohnRayner globalchat "Whataya say to a chance to strike back? I'll let you think about it.";
	Sleep 1.5;



AnswerStrikePositive = Johnrayner addAction 
[

"Yeah, alright. Where do we start?", "ObjectiveHandling\Gen_action.sqf", 

{

ConfirmedStrikeBack = 1; //Variable checked via waituntil. Leads to end of the following user dialogue choices. 
Johnrayner removeaction AnswerStrikePositive; 
Johnrayner removeaction AnswerStrikeTooDangerous; 
Johnrayner removeaction AnswerStrikeTooBusy; 
//These three commands remove dialogue not used anymore - player can't accept offer, -then- start saying he's too busy, or it's too dangerous, nor repeat acceptance. Only works because all three actions are added at the same time.

}

];



AnswerStrikeTooDangerous = 

Johnrayner addAction 

[

"I'd rather not - it sounds dangerous.", "ObjectiveHandling\Gen_action.sqf", 

{

Johnrayner Globalchat 'Suit yourself, buddy.';

NonConfirmedStrike = 1;
JohnRayner removeaction AnswerStrikePositive;
Johnrayner removeaction AnswerStrikeTooDangerous; 
Johnrayner removeaction AnswerStrikeTooBusy;

	//These three commands remove dialogue not used anymore - player can't deny offer, -then- start accepting, nor repeat either type of refusal. 
	//Only works because all three actions are added at the same time.

If (NonConfirmStrikeCancel == 0) then

		//'NonConfirmStrikeCancel' is set to '1' when player re-mentions the strike, so once done, player can't use this deny dialogue.

	{

AnswerRestart = Johnrayner addAction 
		[
		"About that strike...", "ObjectiveHandling\Gen_action.sqf", 

			{
			Johnrayner Globalchat 'So you want in, now?'; 
			NonConfirmStrikeCancel = 1; 
			Johnrayner removeaction AnswerRestart; //So cannot re-mention, again.
			AnswerStrikePositive = Johnrayner addAction ["Yeah, alright. Where do we start?", "ObjectiveHandling\Gen_action.sqf", {ConfirmedStrikeBack = 1; Johnrayner removeaction AnswerStrikePositive}];

			//ConfirmedStrikeBack is used in above in same manner as with initial acceptance - leads to conversation end/acceptance of offer. Removes positive answer so it's not repeated.	

			}
		];

	};

}
];



AnswerStrikeTooBusy  = 

Johnrayner addAction 

[

"I've got better things to do with my time.", "ObjectiveHandling\Gen_action.sqf", 

{

Johnrayner Globalchat 'Get lost.';

NonConfirmedStrike = 1;
JohnRayner removeaction AnswerStrikePositive;
JohnRayner removeaction AnswerStrikeTooDangerous; 
JohnRayner removeaction AnswerStrikeTooBusy;
//These three commands remove dialogue not used anymore - player can't deny offer, -then- start accepting, nor repeat either type of refusal.

If (NonConfirmStrikeCancel == 0) then

//'NonConfirmStrikeCancel' is set to '1' when player re-mentions the strike, so once done, player can't use this deny dialogue.

	{

AnswerRestart = Johnrayner addAction 
		[
		"About that strike...", "ObjectiveHandling\Gen_action.sqf", 

			{
			Johnrayner Globalchat 'So you want in, now?'; 
			NonConfirmStrikeCancel = 1; 
			Johnrayner removeaction AnswerRestart; //So cannot re-mention, again.
			AnswerStrikePositive = Johnrayner addAction ["Yeah, alright. Where do we start?", "ObjectiveHandling\Gen_action.sqf", {ConfirmedStrikeBack = 1; Johnrayner removeaction AnswerStrikePositive}];

			//ConfirmedStrikeBack is used in above in same manner as with initial acceptance - leads to conversation end/acceptance of offer. Removes positive answer so it's not repeated.	

			}
		];

	};

}
];


Waituntil {ConfirmedStrikeBack == 1};
//Waits for player to confirm offer.

Player globalchat "CONVO OVER.";

Apologies for this script :o

- HateDread

Edited by HateDread

Share this post


Link to post
Share on other sites
I think I get the switch, but once you get a received sentence (i.e. the one said in reaction to this: _this kbTell [_from, _topic, "D1_0"];, how do you continue down this dialogue path without returning to the start? (May not make sense - it's 3 am). I still don't understand how this system works... how do you dictate flow?

For example; I want JohnRayner to say "You up for the task, or not?", followed by player choices of "Yes", and "No", with yes leading to further branches like him responding "Good, --info here--", then the player can ask questions about it, whilst the "No" leads to him replying "Fine", and the player having to restart conversation (Maybe with different start - i.e. "Hey, about that task...", then he responds "Oh, you're actually interested now, eh?" and on from there. Does that make sense? (I hope so :/ )

...

The script or fsm is passed several magic variables besides the well-known _this. In the context of the kb system.

_this
- who sent the message.

_from
- what character the message was send to.

_topic
- the topic at hand, the arbitrary label you assigned to the conversation as part of kbAddTopic.

_
sentenceId
- the classname entry you defined in the bikb for a particular sentence.

Your script/FSM takes this information and formulates whatever response you want. The flow comes from each character having files defining their reactions.

A simple example based on your dialog - call it "chatter"

chatter.bikb

 
class Sentences {
 class J_0 {
    text = "Hey!";
    speech[] = {};
    class Arguments {};
 };
 class P_0 {
    text = Uhh, hi.";
    speech[] = {};
    class Arguments {};
 };
 class J_1 {
    text = "So those bastards came after you too, eh?";
    speech[] = {};
    class Arguments {};
 };
 class P_1 {
    text = "I... I think so.";
    speech[] = {};
    class Arguments {};
 };
 class J_2 {
   text = "You 'think so'?";
   speech[] = {};
   class Arguments {};
 };
};

chatter_player.sqf

 
BIS_convMenu = [];

switch (_sentenceId) do {
 case "J_0": {
   _this kbTell [_from, _topic, "P_1"];
 };

 case "J_1": {
   _this kbTell [_from, _topic, "P_2"];
 };

 default {
 };
};

// return the sentence list pool
BIS_convMenu 

chatter_JohnRaynor.sqf

 
BIS_convMenu = [];

switch (_sentenceId) do {
 case "P_0": {
   _this kbTell [_from, _topic, "J_1"];
 };

 case "P_1": {
   _this kbTell [_from, _topic, "J_2"];
 };

 default {
 };
};

// return the sentence list pool
BIS_convMenu 

You would also have FSM files with the same logic flow as the scripts, but those are hard to post in this forum. To humor me, pretend they are out there as well.

In your init you do a kbAddTopic of chatter.bikb for both your characters - using "chatter" as your topic.

 
JohnRaynor kbAddtopic["chatter", "chatter.bikb", "chatter_JohnRaynor.fsm", {call compile preprocessFileLineNumbers "chatter_JohnRaynor.sqf"}];
player kbAddtopic["chatter", "chatter.bikb", "chatter_player.fsm", {call compile preprocessFileLineNumbers "chatter_player.sqf"}];

Then at the appropriate time in your mission scripts/triggers you have JohnRaynor start the conversation and the responses ping-pong back and forth.

 
JohnRaynor kbTell [player, "chatter", "J_0"];

This example is linear in flow, but you certainly could code in branches to reactions to make the dialog go in differing directions.

Share this post


Link to post
Share on other sites

Thank you!

Okay, I'm starting to understand that a bit. Wondering if you sa what I said in my previous post, about the xml? Probably got lost in the drivel I was writing;

hhh, so you recommend the .xmls, then? (Like choosing .sqf over .sqs?) What is the first character(s) in your quote? Looks foreign/unreadable. Apart from that, it seems to make sense, in that part, at least. And, as I started to create one in line with your example, I am wondering, what is the recommended format/syntax for naming them, for organisational purposes? (I.e. where you have STR_DIALOG_BRIEFING_D1_1, and STR_DIALOG_BRIEFING_D1_2, etc; what/why the 'D1_1','D1_2', etc).

Okay, it throws up an error (your example), as I don't have any FSMs. I can understand the idea of flow, using the FSM editor (like a flow chart ^.^), but I don't know how to actually make each 'step'/'section' of the chart equate to anything related to the dialogue (i.e. should I put something in InitCode of each object in the chart?)

- HateDread.

Share this post


Link to post
Share on other sites

The odd character in the leading line of the XML is due to my saving the file in UTF-8 format -I have some Cyrillic later on in that file for a Russian civilian.

There is no recommended name schema really, though I tend to tag with a leading STR_DIALOG just because that seems common elsewhere.

In regard to FSM files... You put your tests ( the cases in the switch ) in condition tests ( yellow diamonds ) and the responses in termination boxes ( the FSM is called, runs and quits until needed again ).

Share this post


Link to post
Share on other sites

Okay, thanks.

What is the odd character meant to be in 'normal' file format? Having just a '<' leads to an error when opening in asy, a browser?

Okay; just thought maybe particular name scheme, i.e. per scene, character, etc.

And I know this is a big ask on top of what you've already done so far, but, if at all possible, would you be able to make an example FSM of the conversation you posted above? I'm in the FSM editor and I know what you're saying, but the specifics/technicalities are not clear, sadly.

If you can't, it's all good, it'll just take a while to work out what's wrong.

Cheers,

- HateDread.

Share this post


Link to post
Share on other sites

As much as I would love him to do that aswell, that would be him basically doing everything. Its crazy...all I wanted to do was add some more immersion into my mission...lol

Share this post


Link to post
Share on other sites

Yeah, that's why I said it's all good if he can't. And I know what you mean! Just a little bit of dialogue, haha, and off we go scripting FSMs, and bikbs. I'm sure others could use the example, though, too, but I'm not sure how much work an FSM is, anyway (I have 0 zero experience with them, hence my asking).

Share this post


Link to post
Share on other sites

There is no special character in a vanilla version stringtable.xml. The first line there would be just

 
<?xml version="1.0" encoding="UTF-8"?>

A counter suggestion to me making the FSM for you, which is quite easy once you are used to that editor. There are plenty of examples in the missions that come with ArmA - unpack the missions.pbo and look in Bootcamp\T02_Parachute_Jump_Training.utes\kb\ and open instructions_BIS_instructor.fsm with the FSM editor. Looking at one would be more effective than my posting a series of screen shots to detail every element's contents in the FSM.

Edited by Evil_Echo

Share this post


Link to post
Share on other sites

:eek:I just did what you said and that made it even more discouraging. lol. Looking at that FSM just takes it to a whole new level.

---------- Post added at 07:08 AM ---------- Previous post was at 06:45 AM ----------

WOW lol. how about that sample???? :P

Share this post


Link to post
Share on other sites

I think I actually get it - Dank, I might be able to help you once I get a hang of this!

Evil, what is the purpose of the knee in the example you showed? (Dank, the 'knee' is the black symbol in the middle). What runs off to the left with 'true', and why?

Also, in the start state, I don't understand

if (isNil "BIS_DEBUG_DIALOG") then {} else

{

textLogFormat["DIALOG- FSM of %1 initiated by %2 sentenceId %3 sentence %4",_this,_from, _sentenceId, localize ("STR_"+"_sentenceId")];

};

And, I don't quite get the actual meaning of (_sentenceId in ["instructions_P_0"]);. So is it checking _sentenceId somwhere, and in the event that it equals "instructions_P_0", cue its respective endstate (In this case, leading to _this kbTell [bIS_player, _topic,"instructions_M_0"];)?

Cheers, mate.

EDIT: Wait, so the quoted example above, is it only a debug code? I.e. if 'BIS_DEBUG_DIALOG', in a textlog, the sentences/fsm-stuff will appear so it can be tracked/debuged.

Edited by HateDread

Share this post


Link to post
Share on other sites

The knee is eye-candy, just keeps the flow diagram neater.

The grey/green ( blind coder here ) diamond on left is a true conditional, the yellow versions are conditional. The idea is that a true conditional is always true, you use that for situations where you want the code to flow on no matter what. In this FSM, it's used for managing defaults, when none of the other tests match up. Note that both types of conditionals have priority fields in them, high priority is checked first and will break ties. The true conditional was set to the default priority of 0, the other conditionals were set to 1. So it fulfills the roles of "default" in a sqf switch statement.

The code in the start state is debugging code to log what is going on. I do similar things myself using diag_log calls. Great way to isolate problems in complicated code.

 
_sentenceId in ["instructions_P_0"]

The "in" test is checking to see if the current value of _sentenceID matches one of the elements in the list given in square braces. Great if you have desire to match more than one case. Otherwise you just as well use

 
_sentenceId == "instructions_P_0"

which is what I normally do, but the other way is a good trick to know about in case you ever need to test against multiple strings at once.

DankTank: I understand the feeling of intimidation by all this, at first it appears overly complex. But like many complex things, once you break it down into smaller tasks the situation becomes more managable. The whole FSM thing can appear that way, but these files are quite useful beyond conversations, as are stringtables. Mastering them opens up a number of doors, especially in higher performance since FSM task scheduling does not suffer some of the restrictions that sqf scripts encounter.

Share this post


Link to post
Share on other sites

I.... actually understand! It maaakes seeense!

Okay, I'm trying to save my compiled FSM, no errors (yay), but which config file do I use? (I tried a few, but when I try to save my FSM, it crashes?)

What does the 'FSM name' do, as separate from the filename?

EDIT: 'An unhandled win32 exception occured in FSMCompiler.exe [2620].'

EDIT#2: I figured it out, gotta use scriptedfsm config!

Okay, with all files in, I get this on mission start, from my .rpt:

Warning Message: No entry 'C:\Documents and Settings\Administrator\My Documents\ArmA 2 Other Profiles\(AEF)HateDread\missions\HATE_Dialogue_Testing.Takistan\kb\chatter.bikb.Arguments'.

Warning Message: No entry 'C:\Documents and Settings\Administrator\My Documents\ArmA 2 Other Profiles\(AEF)HateDread\missions\HATE_Dialogue_Testing.Takistan\kb\chatter.bikb.startWithVocal'.

Warning Message: Size: '/' not an array

Warning Message: No entry 'C:\Documents and Settings\Administrator\My Documents\ArmA 2 Other Profiles\(AEF)HateDread\missions\HATE_Dialogue_Testing.Takistan\kb\chatter.bikb.startWithConsonant'.

Warning Message: Size: '/' not an array

Warning Message: Size: '/' not an array

Warning Message: No entry 'C:\Documents and Settings\Administrator\My Documents\ArmA 2 Other Profiles\(AEF)HateDread\missions\HATE_Dialogue_Testing.Takistan\kb\chatter.bikb.Special'.

Warning Message: No entry 'C:\Documents and Settings\Administrator\My Documents\ArmA 2 Other Profiles\(AEF)HateDread\missions\HATE_Dialogue_Testing.Takistan\kb\chatter.bikb.Arguments'.

Warning Message: No entry 'C:\Documents and Settings\Administrator\My Documents\ArmA 2 Other Profiles\(AEF)HateDread\missions\HATE_Dialogue_Testing.Takistan\kb\chatter.bikb.startWithVocal'.

Warning Message: Size: '/' not an array

Warning Message: No entry 'C:\Documents and Settings\Administrator\My Documents\ArmA 2 Other Profiles\(AEF)HateDread\missions\HATE_Dialogue_Testing.Takistan\kb\chatter.bikb.startWithConsonant'.

Warning Message: Size: '/' not an array

Warning Message: Size: '/' not an array

Warning Message: No entry 'C:\Documents and Settings\Administrator\My Documents\ArmA 2 Other Profiles\(AEF)HateDread\missions\HATE_Dialogue_Testing.Takistan\kb\chatter.bikb.Special'.

Bikb looks like this (Now edited to avoid mistakes. Ignore):

class Sentences {

class STR_DIALOG_Chatter_J_0 {

text = "Hey!";

speech[] = {};

class Arguments {};

};

class STR_DIALOG_Chatter_P_0 {

text = "Uhh, hi.";

speech[] = {};

class Arguments {};

};

class STR_DIALOG_Chatter_J_1 {

text = "So those bastards came after you too, eh?";

speech[] = {};

class Arguments {};

};

class STR_DIALOG_Chatter_P_1 {

text = "I... I think so.";

speech[] = {};

class Arguments {};

};

class STR_DIALOG_Chatter_J_2 {

text = "You 'think so'?";

speech[] = {};

class Arguments {};

};

};

class Arguments{};

class Special {};

startWithVocal[] = {};

startWithConsonant[] = {};

Also, in an FSM example, in one of the endstates, why have '_this kbTell [_from, _topic,"instructions_C_0"];' yet sometimes '_this kbTell [bIS_player, _topic,"instructions_M_0"];'? Is it because in the second example, the instructor is talking to someone different to the person who spoke to him last? Also, do I not need to redefine the topic each time, then, i.e. only when I change it?

EDIT#~

I got it working! Finally, conversational FLOW! Thank you Evil! Your patience is amazing.

How do I get a specific name to show when the character is talking via kbtell, i.e. 'John Rayner"? 'Setidentity' in description.ext doesn't do it.

Edited by HateDread

Share this post


Link to post
Share on other sites

You're welcome. Congrats on getting it working.

I use setIdentity and description.ext for my stuff. Seems to work mostly.

Share this post


Link to post
Share on other sites

The setIdentity name seems to work with direct conversation with kbTell/FSM, but if the conversation is over the radio then call signs are used. Use setGroupID on the group leader to give a radio call sign. It's nice how the FSM will automatically use direct conversation or radio based on distance.

Share this post


Link to post
Share on other sites

Hmm, with unit JohnRayner, with John Rayner in it's description field, I have in my description.ext;

class CfgIdentities

{

class JohnRayner

{

name = "John Rayner";

face = "Face48";

glasses = "None";

speaker = "Adam";

pitch = 0.9;

};

};

And also in init.sqf (out of desperation);

JohnRaynerGroup = group JohnRayner;

JohnRaynerGroup setgroupId ["John Rayner"];

Yet, still, when kbtell-ing, it shows the default name assigned (i.e. a Takistani one instead of John Rayner).

Share this post


Link to post
Share on other sites

Believe AZcoder is correct about this.

HD - did you also check whether you are using SetIdentity in the init field of JohnRayner or via your init script?

Edited by Evil_Echo

Share this post


Link to post
Share on other sites

Please sign in to comment

You will be able to leave a comment after signing in



Sign In Now

×