How do you set up a scripted conversation between two or more NPCs?

From the Oblivion ConstructionSet Wiki
Jump to navigation Jump to search

A basic scripted conversation between two NPCs is fairly simple to set up. Getting three or more NPCs to talk to each other, particularly if you want them to do something besides stand still, is more complicated. We'll cover all of these possibilities, starting with the simplest.


Creating a basic scripted conversation between two NPCs.[edit | edit source]

There are two simple ways to get NPCs to talk to each other:

  • An NPC with a Find package targeting another NPC will automatically start a conversation with the second NPC, beginning with the HELLO conversation topic. This is the same way that NPCs start random conversations with each other.
  • Use StartConversation to trigger the conversation. This can be useful if you want to start the conversation with a custom topic (i.e. something besides HELLO).


In order to force the NPCs to have a particular conversation, you need to set up the dialogue infos that they will use so that they link together into a complete conversation. The basic principles are as follows:

1. The simplest way to make a conversation is to create a new topic for each response on the Conversation tab of the Quest window, create an info under each topic, and use the "Link To" and "Link From" fields to link the infos together in the order that you want them to be spoken. This is fine for a very short conversation, but creating a new topic for each info can become cumbersome for longer conversations.

2. A more sophisiticated way (and the way most conversations in Oblivion were created) is to use a single topic, with the infos conditionalized on a variable which is incremented in the results field of each info. Look at the Conversation tab of the MSConversations quest in the Oblivion master file for some examples of how this is done. The importants steps are as follows:

  • You'll need to create the conversation in a quest which is marked to "Allow repeated conversation topics" (see Quest Data Tab) -- normally, the game will not use the same topic twice in the same conversation (as a way to avoid repetition in random conversations), but in this case we want to use the same topic repeatedly in created our scripted conversation. (In our example, MSConversations is a quest created for all miscellaneous quests to use for scripted conversations.)
  • On the Conversation tab, create a topic for your conversation (say MS40Conversation). Now create the starting info for your conversation (assuming you are using StartConversation -- if you are using a Find package, the first info will have to be a HELLO, which can then link to your custom topic).
  • Create a quest variable to track the progress of the conversation (say MS40.convo). Conditionalize the first info with this variable (GetQuestVariable MS40.convo == 0), plus whatever additional variables are necessary (e.g. GetIsID, GetStage, etc.).
  • Make sure the "Run immediately" box is checked. This tells the game to run the results when the conversation is being created, instead of when it is spoken. Without this checkbox, the variable which we are using to conditionalize the conversation will not be incremented and the conversation will not work.
  • In the "Link To" field, add your custom converation topic -- we are going to link the topic to itself for the whole conversation. Since this is the start of the conversation, leave the "Link From" field blank.
  • In the results field, increment your variable (e.g. set MS40.convo to MS40.convo + 1) so that the next info (which we are about to create) will now pass its conditions.
  • Assuming you want the NPCs to trade off speaking, leave the "Next Speaker" as "Target" (if you want an NPC to speak more than one line in a row, you can change that to "Self").
  • Now that we've created a good template, copy that info and change the text to the next line in the conversation. We only have to make two other changes to this new info: (a) Add our custom topic to the "Link From" field (so that it can link from the first info), and (b) change the condition (e.g. GetQuestVariable MS40.conv == 1).
  • Repeat this process for the rest of the conversation. The final info in the conversation should have its "Link To" field left blank, and have "Goodbye" checked to indicate that it serves as the end of the conversation (otherwise the game will automatically tack on a random GOODBYE).



Creating a speech by a single NPC[edit | edit source]

Setting up a "speech" by an NPC (where he is the only one talking) is actually a variant of the process given above. You can either use StartConversation to tell him to talk to himself (e.g. BurdRef.Startconversation BurdRef), or set up the conversation so that all the infos are "Next Speaker: Self" (e.g. you have a second NPC present, but he never speaks).


Creating a conversation between multiple NPCs[edit | edit source]

Getting more than two NPCs to talk to each other, or getting NPCs to talk and move at the same time, requires abandoning the game's conversation generator completely, and handling everything by script. The key commands here are Say and SayTo, in combination with script timers which track when it is time for the next NPC to speak. All the NPC conversations in the character creation sequence were handled in this way.

  • Create a quest script to run the main timer, and track the conversation variables (see CharGenQuest script). The main timer is a standard script timer:
begin gamemode
	; count down timer
	if convTimer > 0
		 set convTimer to convTimer - getSecondsPassed
	 endif
end
  • Create a variable in the quest script to track whose turn it is to speak. For example, in the CharGenQuest script:
; used by conversation scripts to tell whose turn to speak
short speaker
short target
; 1 = Baurus
; 2 = Renote
; 3 = Glenroy
; 4 = Emperor
; 5 = player (as target)
  • In each NPC's script, add a section which is looking for the quest variable to tell them it is time to speak. Say and SayTo return the time (in seconds) that the specified dialogue will take to speak, so the NPC's script sets the quest timer variable as well. For example, in Glenroy's script:
begin gamemode

; talk when it is time
if CharacterGen.speaker == 3 && CharacterGen.convTimer <= 0
	set target to CharacterGen.target

	if target == 0
		set CharacterGen.convTimer to Say CharGenMain 1
	elseif target == 1
		set CharacterGen.convTimer to SayTo BaurusRef, CharGenMain 1
	elseif target == 2
		set CharacterGen.convTimer to SayTo RenoteRef, CharGenMain 1
	elseif target == 3
		set CharacterGen.convTimer to SayTo GlenroyRef, CharGenMain 1
	elseif target == 4
		set CharacterGen.convTimer to SayTo UrielSeptimRef, CharGenMain 1
	elseif target == 5
		set CharacterGen.convTimer to SayTo player, CharGenMain 1
	endif	

endif
end
  • The last step is to actually create the dialogue. Each info should be conditionalized both on the speaker and a tracking variable (so that you can use a single topic in your scripts, e.g. CharGenMain). The results field of each info increments the tracking variable, and sets the speaker and target variables (if necessary) for the next speaker. For example:
set characterGen.convCount to characterGen.convCount + 1
set characterGen.speaker to 1 ; Baurus
set characterGen.target to 2 ; Renote


See the CharacterGen quest, CharGenMain topic for an extensive example.


Another Strategy For Speeches and Conversations Between Multiple NPCs[edit | edit source]

This method deals mostly for cases where you have actors who are not near each other eg. two persons/groups shouting at each other from opposite sides of the road.

Similar to above, but a bit less complicated, another way to approach this is to first setup the quest script with just a variable defined. For our purposes, we'll just use the variable (short) nuline. Save that script, and attach it to your quest. Then have all your dialogues created in the order you want them spoken, setting up a condition of who you want to speak them, and adding a condition using the quest variable nuline. Using that variable, make every new dialogue assigned to a new value of this variable eg. first dialogue uses a value of 1, second dialogue uses a value of 2, and so on. Now, you have a clean list of all the dialogues, in order. (By creating them in the order they are to be spoken, you can keep them viewed in that order. It also makes it easier, when you have to figure out what sound files go with what dialogues since they will be sequential)

The way that this method differs from what is mentioned above is that most of the nuts and bolts is in the result script of each dialogue, allowing for finer tuning, and less clutter in the quest script.

Going back to the quest scripting, you will now need to add a small portion so that new lines will be called when the old one finishes. Every dialogue you defined previously needs to be called individually, normal conversation handling will not be kicking in since you will be having NPCs who are essentially talking to themselves, or talking at another NPC. First things first, you'll need to add the variables ref speaker, ref target, and float convtimer to the top of your quest script. The purpose of all of these will be similar to above, since it will use similar scripting, but they will be handled slightly different, being that the speaker and target are now being defined as references instead of just numbers to be interpreted by the quest script.

The scripting to add to your quest should look something like

if convTimer > 0
		set convTimer to convTimer - getSecondsPassed
elseif speaker > 0
		if target == 0
			set convTimer to speaker.Say <topic>, 1
		else
			set convTimer to speaker.SayTo target <topic>, 1
		target.look speaker
		endif
endif

The flag at the end of say and sayto is to force subtitles, which is usually a good idea given how your dialogue may not be voiced at this point, if at all.

The remaining working will be done within the result script of each of the dialogues. Within each result script area, you should always have 2 things;

set <quest>.nuline to <quest>.nuline + 1

and

set <quest>.convTimer to <duration of sound file +/- a few seconds>

The first line is there to help the dialogue proceed to the next line after it has been spoken. The second line is there to further refine the timing between this dialogue and the next, and allowing for momentary pauses. Until you have sound files created or generated, you can just use an estimate as to how long you think that line will be spoken for. You can always adjust this later, in some cases, it may be gotten rid of all together if the pause seems to take too long.

(the convtimer part within the quest script is still needed to prevent the same line being looped in certain circumstances)

In addition to those 2 things, you also need to do some more work in the result script to setup the next dialogue to be spoken. These should be included in the result script of any dialogue for which there is a change of speaker or target for the next dialogue.

set <quest>.speaker to <ref to speak the next line>

set <quest>.target to <ref who will be spoken to (0 if none)>

If the dialogue is supposed to pause until after an event takes place, you do not need to include these lines, but instead directly call <speaker>.sayto <target> <topic> within separate scripting when that event is done (such as a quest stage update). During such a time that you don't want any lines spoken, you should set the <quest>.speaker to 0, and <quest>.nuline to some value which is not used by any dialogues. You can also use another condition in the quest script to act as a switch to turn on and off the portion that controls calling the next dialogue (the bit mentioned earlier).


This method is a bit easier to apply to your standard quest since you can rather easily add additional lines or speakers without having to go back to the quest script to register a new reference, all you have to do is adjust the result script to point to a different speaker, and change the nuline conditions for dialogues that take place afterward. This method is also a bit easier to understand since it is presented without the context of existing quests.