Jump to content
Sign in to follow this  
Domi

Some Tips and Tricks on Creating D-files

Recommended Posts

This one is a file I created when I had a few people new to coding to help out with dialogue file coding. I figured that some people may find it helpful. Note, that I usually say 'coding' when I mean writing D-file' and 'scripting' when I speak of BAF's. This tutorial do not cover anything to do with scripting.

 

Some Tips and Tricks

 

Tools You Need: WeiDU (Weimer Dialogue Utility), NI (Near Infinity) and IESDP (Infinity Engine Description Project)

 

D-FILE SYNTAXIS

 

All this information can be found in Road to Banter Tutorial (by JC and Blue) and WeiDU Documantation (by Wes Weimer).

 

For the character to talk he or she needs a DIALOGUE FILE. Dialogue Files are of 2 sorts: INTERPARTY BANTER (called from the script by command Interact()) OR if they have no special conditions attached (and therefore do not require script) run by the engine and ALL OTHER BANTER (called from the Script by Dialogue() or StartDialogueNoSet()) I usually put all the banters between the characters into B-file and use Interact() to summon the ones that require SCRIPT. All other talks I place into J file and call for by Dialogue() commands. The Dialogue() command will force CREATURE to walk towards the person he is going to talk to. DialogueNoSet() will fire it ‘on spot’

 

The TWO useful syntaxes to write a D-file are: CHAIN and SAY. CHAIN is useful when you have lots of characters talking. SAY is good when you have NPC talking ONLY to PC. Your full dialogue can use a combination of SAY and CHAIN, depending on what you need.

 

Both CHAIN and SAY can be used to initiate a dialogue or be a block that is ‘sent to’ from an earlier one. The difference is in how the “top†is handled. No conditions on a dialogue block which is shown by using a double tilde after IF (like this: IF ~~ ) means that the block can not be used to start a conversation.

 

Let us look at a simple CHAIN.

 

CHAIN

IF WEIGHT #-1 ~InParty("AJANTIS")

See("AJANTIS")

!StateCheck("AJANTIS",STATE_SLEEPING)

AreaType(FOREST)

TineofDay(DAY)

Global("XZAJ1","LOCALS",0)~ THEN ~_BXZAR~ XZAJ1

~Sir Paladin, quickly! A dragon!~ [XZAR99]

DO ~SetGlobal("XZAJ1","LOCALS",1)~

== ~_BAJANT~ ~Eh, what? I see nothing.~

== ~_BXZAR~ ~There! In that gorse bush!~

== ~_BAJANT~ ~Your mockery is repellent as is all else about you. You see clearly enough that I am a paladin but feign to believe that a sparrow is a dragon.~

== ~_BXZAR~ ~Ah, your pardon, sirrah; curse these wandering senses of mine. I perceive now that I was twice mistaken.~

== ~_BAJANT~ ~Twice?!~

== ~_BXZAR~ ~Indeed. For an instant, I had truly believed yon twitting avian to be a paladin.~

EXIT

 

This is one coded dialogue from b-file. B-file contains all dialogues initiated by an NPC (in this case Xzar)

 

CHAIN

IF WEIGHT #-1 ~InParty("AJANTIS")

See("AJANTIS")

!StateCheck("AJANTIS",STATE_SLEEPING)

 

The beginning is always the same – shows whom with Xzar is going to talk to. Please, note that there is a bunch of stuff in tildes after IF – that’s mean that the first line of this CHAIN can serve to initiate a conversation and if the dialogue was scripted, then it will show up when called for (or when it has the condition that script has and is the top most or lowest weight one! It causes major headaches sometimes, so be careful to set up your conditions properly!)

 

If, for example Skie and Ajantis BOTH will have to be there – you will have the conditions set as shown below:

 

 

CHAIN

IF WEIGHT #-1 ~InParty("AJANTIS")

See("AJANTIS")

!StateCheck("AJANTIS",STATE_SLEEPING)

InParty("SKIE")

See("SKIE")

!StateCheck("SKIE",STATE_SLEEPING)

 

Note: “!†means “notâ€Â, in this case Ajantis and Skie are not sleeping

 

AreaType(FOREST)

TineofDay(DAY)

 

Those are Triggers. First tells you that the dialogue has to happen in the forest and the second one – that in the Daytime.

 

 

Where do you take triggers?

 

One word IESDP:

 

http://iesdp.gibberlings3.net/

 

 

Tokens (<CHARNAME>, <PRO_HESHE>, etc – where the game automatically put in the name, He/She etc of the PC are here:)

 

http://iesdp.gibberlings3.net/scripting/tokens.htm

 

Please note, that if you start a sentence with a TOKEN, it will still display first letter in low case. Conclusion: DO NOT START sentence with a TOKEN

 

IDS files (areatype etc) – those are the files browsable with Near Infinity as well as published in some places on the net (as on the site below)– gives you the types of Area, time of day etc – ie the variable in the parenthesis of the trigger. Usually the parameter you fish out of IDS is used without QUOTES ie AreaType(FOREST).

 

All IDS are collected in the IDS folder which you can browse with your NI Editor.

 

Really good BG1 walk-through is here:

 

http://www.dudleyville.com/bg1/index.htm

 

Tutorials:

 

General Page: PPG, FW, G3 all have separate forums for that stuff!

 

 

Rode to Banter (NPC-NPC talks):

 

Tutorial na Bantera “Road to Banter†is the single best tutorial on dialogue coding.

 

Global("XZAJ1","LOCALS",0)~ THEN ~_BXZAR~ XZAJ1

 

This line is very important! It asks the game if the banter has happened ALREADY! (Local = 0 means that nope, it did not!)

 

The naming of the files: first two letters of character’s name, starting with the NPC who initiates conversation. XZAJ means that XZ starts the conversatiuon with Ajantis. And then just count the banters: 1, 2 or whatever. XZAJ1 – first talk, XZAJ2 – second etc.

 

Note! It is a good idea to name all your GLOBALs using your personal PREFIX (ie all globals introduced by BG1NPC project should start with X#)

 

~_BXZAR~ is the name of the file to which the dialogue is going to. Tildas and underscores are there because of TUTU compatibility. Pure BG2 does not use them, like that: == BAJANT ~: New versions of WeiDU allow us to go the way of BG2, so it is not necessary anymore to enclose your FILE NAME in tildes (~)

 

ie == _BXZAR ~ is perfectly acceptable in TUTU

 

 

~Sir Paladin, quickly! A dragon!~ [XZAR99]

 

That’s the first line Xzar will say. In the square parentheses is the musical theme associated with the character.

 

DO ~SetGlobal("XZAJ1","LOCALS",1)~

 

This line changes Global from 0 to 1 to tell the game that the conversation did occur already.

 

This is the first time we are discussing operator DO. DO in the dialogue is used when you need simple actions performed, like setting GLOBAL or making character leave the screen. IESDP in its Actions subdivision documents all ACTIONS that will work with DO. To use DO with a CHAIN, just insert it anywhere in exactly the same fasion as shown. The action will occur after the dialogue is over. If it is important to have the action occurring after a certain phrase, we can do the following:

 

== ~_BAJANT~ ~Eh, what? I see nothing.~

END

IF ~~ THEN DO ~ SetGlobal("XZAJ1","LOCALS",1)~ EXTERN _BXZAR StateName

 

(we will talk about EXTERN more later on)

 

== ~_BAJANT~ ~Eh, what? I see nothing.~

== ~_BXZAR~ ~There! In that gorse bush!~

 

Those lines are “who says what†and transfer between files.

 

If a third character has something to say but it is not necessary for conversation to occur, then use this line:

 

== ~_BMONTA~ ~IF ~InParty("MONTARON")~ THEN ~text text text~

 

If the paragraph is too big, then use:

~ where you break it up and strat next line with:

= ~

 

== ~_BAJANT~ ~Eh, what? I see nothing.~

= ~and I really want to say much, much, much more about that, Xzar…~

== ~_BXZAR~ ~There! In that gorse bush!~

 

== ~_BXZAR~ ~Indeed. For an instant, I had truly believed yon twitting avian to be a paladin.~

EXIT

 

EXIT tells the game to get the hell out of DIALOGUE MODE! Ie that will finish the banter for us.

 

HOW TO INTRODUCE PC SPEECH?

 

CHAIN can handle PC responses or different actions… Let us say I want PC to interfere after Xzar said:

 

== ~_BXZAR~ ~Indeed. For an instant, I had truly believed yon twitting avian to be a paladin.~

 

Now, we cannot EXIT from dialogue mode. So we will use a neat command, called END instead and add PC response after it:

 

== ~_BXZAR~ ~Indeed. For an instant, I had truly believed yon twitting avian to be a paladin.~

END

IF ~~ THEN REPLY ~I, PC, have something to say~ EXIT

 

The line is finished by EXIT option. But what if we want to let XZAR put in another word? Well… we can GOTO to XZAR’s remark, like this:

 

== ~_BXZAR~ ~Indeed. For an instant, I had truly believed yon twitting avian to be a paladin.~

END

IF ~~ THEN REPLY ~I, PC, have something to say~ GOTO XzarReplyPC

 

And in the B-file we need to add that Xzar’s Reply. XzarReplyPC is called STATE NAME. Make sure that all STATE NAMES are different. You can sent multiple PC options to the same STAET NAME. If you send to a non-existent STATE name it will hick up WeiDU as well (surprise, surprise!)

 

Let’s consider the situation where XZAR only talks to a PC after out CHAIN. That calls for syntaxes with SAY. SAY does not have the FILE NAME in its SYNTAXIS so to indicate which file SAY is attached to we use APPEND command:

 

APPEND _BXZAR

 

IF ~~ XzarReplyPC

SAY ~And here is Xzar’s Reply~

IF ~~ THEN REPLY ~I, PC, have something to say~ GOTO XzarReplyPC1

IF ~Race(Player1,ELF)~ THEN REPLY ~I am an Elf and I have my special reply!~ GOTO XzarReplyPC2

IF ~~ THEN REPLY ~And I do not want to talk to anyone any more~ EXIT

IF ~~ THEN REPLY ~And I want to use a DO function!~ DO ~SetGlobal(“X#XzarGlobalâ€Â,GLOBALâ€Â,1)~ EXIT

IF ~InParty(“Ajantisâ€Â)~ THEN REPLY ~And I want to show you how to use EXTERN~ EXTERN _BAJANT AjantisReplyPC

END

 

Note, that when we use SAY syntax, every block is started without mentioning file name (in case of CHAIN we had IF ~~ THEN _BXZAR XzarReplyPC) and is finished by END.

 

Please, also note that this BLOCK cannot initiate a dialogue. Tildas after IF are empty! A block that would have started a dialogue will look like this:

 

IF ~Global(“X#XzarStartTalkingâ€Â,â€ÂGLOBALâ€Â)~ XzarReplyPC

SAY ~And here is Xzar’s Reply~

 

Please, note that it’s NOT a good idea to have ANYTHING but GLOBAL value in IF condition on scripted dialogues with SAY. Set every condition up in the script.

 

 

And now comments to every one of PC replies:

 

First one sends you to Xzar’s reply XzarReplyPC1 on _BXZAR file!

Second one will only be showing up if the player1 is an ELF (setting conditions just like in the ‘top’ of the CHAIN, via IESDP options called TRIGGERs)

Third one is an option, which will kick us out of conversation

Fourth one shows how to use DO operator after PC reply

Fifth demonstrates the use of EXTERN EXTERN is the same as GOTO, but is used when we need to switch from file to file. If I used a GOTO after that line, I would have send the program to search AjantisReplyPC in _BXZAR file! But I want Ajantis to speak, therefore, I use EXTERN and specify which file I want to cross to after it.

 

What if we do NOT want PC to speak after a SAY block?

 

IF ~~ XzarReplyPC

SAY ~And here is Xzar’s Reply~

IF ~~ THEN EXIT

END

 

Is the construction you want.

 

And, if we want to use DO operator before getting out then, you guessed! It will be:

 

IF ~~ XzarReplyPC

SAY ~And here is Xzar’s Reply~

IF ~~ THEN DO ~SetGlobal(“X#XzarGlobalâ€Â,GLOBALâ€Â,1)~ EXIT

END

 

 

 

USE of SHORTHAND

 

If you look on the files of a old-timer modder you will often see a bunch of +

 

Well, it’s a neat thingy called SHORTHAND that JC once suggested to Wes.

 

IF ~~ THEN REPLY in shorthand is ++ (double plus)

 

IF ~InParty(“Minscâ€Â)~ THEN REPLY in SHORTHAND is IF ~InParty(“Minscâ€Â)~ +

 

GOTO in SHORTHAND is + (single plus)

 

There s no shorthand for IF ~~ THEN EXIT or IF ~~ THEN DO

 

Interjections in its simplest incarnation are CHAINs only "inserted" into the existing text.

 

Here is an example of a simple interjection and below is the explanation of what's going on:

 

Please, note, this example uses IsValidForPartyDialogue("Kivan") throughout. It is not a good command, use the combination of:

InParty(“Kivanâ€Â) !Dead(“Kivanâ€Â) !StateCheck("Kivan",STATE_SLEEPING)

 

INTERJECT_COPY_TRANS ~_KELDDA~ 0 X#KivanKeldath

== ~_KIVANJ~ IF ~IsValidForPartyDialogue("Kivan")~ THEN ~Fair is your temple and full of hope, priest.~

== ~_KELDDA~ IF ~IsValidForPartyDialogue("Kivan")~ THEN ~And have you forsaken hope, my son?~

== ~_KIVANJ~ IF ~IsValidForPartyDialogue("Kivan")~ THEN ~I have hope but it lies beyond this plane, Keldath Ormlyr~

== ~_KELDDA~ IF ~IsValidForPartyDialogue("Kivan")~ THEN ~Gaze upon the sun as it rises, elf. It is born anew every morn - here and everywhere in this world... on this plane. Rejoice, for you are blessed by its rays.~

END

 

INTERJECT_COPY_TRANS

 

that's the command that seeks out the specific "state" on the file named:

~_KELDDA~

 

Please, note that if you are interjecting after a STATE that has a single action woth one DO function after it, you should be using (ie a DO something and EXIT state)

 

INTERJECT_COPY_TRANS2

 

In SHORTHAND INTERJECT_COPY_TRANS will be I_C_T and guess what will I_C_T2 stands for?

 

 

And here is this state (or simply the number of the line after which you want to interject:

 

0

 

if you look into the _KELDDA.D you will see:

 

IF WEIGHT #3 /* Triggers after states #: 1 2 6 even though they appear after this state */

~True()

~ THEN BEGIN 0 // Here is your state number! IE, you will be asking to insert your lines after that particular phrase.

SAY #77961 /* ~Welcome! The traveling adventurer is never turned away from a house of Lathander, as we strive to aid all who make a difference in the Realms. If you are battle-worn we can extend a number of necromantic restorations, whatever your need. A small donation is all the compensation that we require. If you wish nothing then let me tell you of the madman Bassilus.~ */

//Here is where the shown code will stick in Kivan - Keldoth conversation

IF ~~ THEN REPLY #77962 /* ~What kind of aid can you give us?~ */ DO ~StartStore("_TEM3402",LastTalkedToBy(Myself))

~ EXIT

IF ~!Dead("bassilus")

~ THEN REPLY #77963 /* ~We don't require any help at the moment. ~ */ GOTO 8

IF ~Dead("bassilus")

~ THEN REPLY #77963 /* ~We don't require any help at the moment. ~ */ EXIT

END

 

 

X#KivanKeldath

simply the name of the interjection. They should be unique and start with your prefix, since WeiDU will transform it into a GLOBAL.

 

== ~_KIVANJ~ IF ~IsValidForPartyDialogue("Kivan")~ THEN ~Fair is your temple and full of hope, priest.~

 

and here is the syntax - it is exactly the same as the CHAIN. Make sure that the condition IF-THEN is the same throughout. Please, note that traditionally J-files are used for handling interjections. All J file names are listed in PDIALOGUE.2DA file you can access via NI (in 2DA folder)

 

 

Where can you take the D files to look up their names (I already listed the states)?

 

It is done in a few stages:

1) open NI and find the CRE of the character which you interject with. F.ex: Elminster. You will find a bunch of CRE's for him; the ones that are from BG1 are the ones that have _ in front of them. Since I want to interject with Elminster in Chapter 3, I pick the _ELMIN3.CRE. When you open it up you will see that the dialogue assigned to him is _ELMIN3.DLG.

2) Write down the name of the dlg file.

3) open WeiDU. After the command line enter the command:

weidu _elmin3.dlg

the _elmin3.d will be created in the BG2 main folder.

 

 

EXTEND_BOTTOM

 

Is another useful command that allows you to add whatever you want after a STATE. For example, if I wanted to add PC replies after ~_KELDDA~ 0 it would look like:

 

EXTEND_BOTTOM ~_KELDDA~ 0

IF ~~ THEN REPLY ~Whatever~ EXIT

END

 

 

Other useful commands for D-files are:

 

ADD_TRANSACTION_TRIGGER

ADD_STATE_TRGGER

INTERJECT

JOURNAL

ADD_TRANS_ACTION

REPLACE_STATE_TRIGGER

 

Useful Reading:

 

Sim's Complete Scripting Guide (scripting!)

Ghreyfain's A Beginner's Guide to NPC Creation with WeiDU (explains file structure very well and gives simple examples of SAY dialogues)

Blue's and JC's Road to Banter (covers CHAIN in detail)

Japeth's State Weights (covers WEIGHTs)

JC's Another look at WEIGHTs (covers WEIGHTs)

Rastor's romance Authoring Tutorial (shows how to combine D and BAF to run a standard romance sequence with timered dialogues, dream scripts and flirts)

WeiDU Documentation (the bestselling mystery novel)

Edited by Domi

Share this post


Link to post

That's a very helpful script, Domi, and I'll happily recommend it to any person who might ask me about starting help with D-file writing in future!

 

Nitpicky nitpick: "TineofDay(DAY)" should be "TimeofDay(DAY)" :)

Share this post


Link to post
Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Sign in to follow this  

×
×
  • Create New...