Author Topic: IWD engine: dialogue coding  (Read 3706 times)

Offline Kulyok

  • Global Moderator
  • Planewalker
  • *****
  • Posts: 6248
  • Gender: Female
  • The perfect moment is now.
IWD engine: dialogue coding
« on: March 21, 2008, 08:08:56 AM »
(I'm mostly accumulating the_bigg's(Avenger's, CamDawg's, devSin's, igi's(IESDP), jcompton's) code here, hoping it may be useful in the future. Note that it may not be as useful for IWD2, because IWD2 has some nifty functions of its own and you'll be better off perusing Domi's code.)

0) Dialogue with non-joinable NPCs.

Same as BG2, but note that some triggers and actions that work in BG2 do NOT work for IWD. Check IESDP for more details: http://iesdp.gibberlings3.net

1) Banters.

a) There are no "real" timers, only "game" ones. This means you cannot set a RealSetGlobalTimer() for one real hour, but you can set a timer for one game day. Note that from my experience, even the existing timers seem to be quite capricious, especially if you are setting a timer for one(or two) game hours.

b) There is no banter engine, which randomly triggers banters, aka BG2. It means that all banters between party members have to be scripted.

c) This is very important: in IWD, party NPC scripts do NOT work during the time the player issues commands. It means that as long as the player keeps clicking on his party members, ordering them around, they will NOT talk. They will only talk if the party stops.

Why am I telling you this? Well, inconvenience aside, it means that every banter has to be scripted this way(an example between Teri and Nella):

IF
InParty(Myself)
Global("A#NPCNellaTeri1","GLOBAL",1)
InParty("A#Nella")
Detect("A#Nella")
!Detect([ENEMY])
!StateCheck(Myself,CD_STATE_NOTVALID)
!StateCheck("A#Nella",CD_STATE_NOTVALID)
THEN
RESPONSE #100
StartDialogueNoSet("A#Nella")
END

- for as long as the variable A#NellaTeri1 is 1, Teri will keep trying to talk to Nella. Otherwise, she'd try once, and the dialogue may never trigger(or start stacking in her player-initiated dialogue slot, which is just as unpleasant, see "How to make sure your banters run when you want them to")

In the dialogue, use

CHAIN IF ~Global("A#NPCNellaTeri1","GLOBAL",1)~ THEN A#TERI nt1
~(text)~ [audio]
DO ~SetGlobal("A#NPCNellaTeri1","GLOBAL",2)~

... and so on.

But an important point: where do we set this variable in the first place? I have two answers: either, again, via Teri's script(see the link to the tutorial above), or via the area script. The latter will mean that AR2100 will have the following block appended on top:

IF
Global("A#NPCNellaTeri1","GLOBAL",0)
InParty("A#Nella")
InParty("A#Teri")
THEN
RESPONSE #100
SetGlobal("A#NPCNellaTeri1","GLOBAL",1)
Continue() // continue, as not to interfere with OnCreation() block
END

(Why on top? Why EXTEND_TOP, not EXTEND_BOTTOM? Because with EXTEND_BOTTOM, your blocks will never be executed correctly, if another mod adds a block that is always true on top of it, which happened.)

Note carefully: if Player1(PC) is participating in the dialogue, you have to 1) check that Player1 is able to talk; 2) even if it's an NPC-NPC banter, dialogue should be initiated via StartDialogueNoSet(Player1).

If you use StartDialogueNoSet("A#Nella") instead, do not be surprised if your replies show as "Nella- (reply)" on the dialogue screen.

2) Interjections.

the_bigg takes full credit for this.

a) Interjections into a state with no replies: same as in BG2. Read Weidu readme at http://weidu.org

b) Interjections into a state WITH PC replies.

You'll need three files. First file, A#Dump.d, will look like this:

BEGIN A#DUMP
IF ~~ 0   SAY ~T~ IF ~~ THEN EXIT END
IF ~~ 1   SAY ~T~ IF ~~ THEN EXIT END
IF ~~ 2   SAY ~T~ IF ~~ THEN EXIT END
IF ~~ 3   SAY ~T~ IF ~~ THEN EXIT END
IF ~~ 4   SAY ~T~ IF ~~ THEN EXIT END
IF ~~ 5   SAY ~T~ IF ~~ THEN EXIT END
IF ~~ 6   SAY ~T~ IF ~~ THEN EXIT END
IF ~~ 7   SAY ~T~ IF ~~ THEN EXIT END
IF ~~ 8   SAY ~T~ IF ~~ THEN EXIT END
IF ~~ 9   SAY ~T~ IF ~~ THEN EXIT END
IF ~~ 10  SAY ~T~ IF ~~ THEN EXIT END
IF ~~ 11  SAY ~T~ IF ~~ THEN EXIT END
IF ~~ 12  SAY ~T~ IF ~~ THEN EXIT END
IF ~~ 13  SAY ~T~ IF ~~ THEN EXIT END
IF ~~ 14  SAY ~T~ IF ~~ THEN EXIT END
...
(~T~ is not necessary - it's my indication for "Temp". Choose anything you like. :) )

Yes, you guessed correctly: each line for each interjection. Now, watch my hands...

For each interjection, we are doing the following: first, we are "saving" the existing replies into a dump state(that's what we need A#dump for), then we disable them. How? It's simple: we add an "if this NPC is not available right now" condition, so they show ONLY if NPC is not available for the interjection), and if the said NPC IS present, we let him speak: we add an EXTEND_BOTTOM where he speaks his mind, and then we COPY_TRANS back.

Too much information too fast? Let's take an example:

Korin is talking to Sister Accalia. He wants to say his piece before PC does. Now, we add a line to Replace.d:

REPLACE A#DUMP IF ~~ THEN 0   SAY ~T~ COPY_TRANS DACCALIA 2  END END // this means we save Accalia's original replies

And now we add another line to Replace.d:

ADD_TRANS_TRIGGER DACCALIA 2  ~OR(3) !InParty("A#Korin") !Detect("A#Korin") StateCheck("A#Korin",CD_STATE_NOTVALID)~ // if Korin is not available, Accalia's replies will show. But if he IS available and is able to speak, Accalia's replies will NOT show. This is essential for his interjection to work correctly.

And now, the actual interjection in Interjections.d:

EXTEND_BOTTOM DACCALIA 2
IF ~InParty("a#Korin") Detect("a#Korin") !StateCheck("a#Korin",CD_STATE_NOTVALID)~ EXTERN A#KORIN A#KorinDACCALIA2
END

CHAIN A#KORIN A#KorinDACCALIA2
~I have seen one of these rituals, once.  It is an imposing sight, almost to the point of being frightening.  All the fallen heroes...  I could almost see them calling from beyond the sun and the stars.~
== DACCALIA ~Your friend speaks truly.~
END
COPY_TRANS A#DUMP 0

And in .tp2, we compile these files separately:

COMPILE ~Mod/Dialogue/A#Dump.d~
COMPILE ~Mod/Dialogue/Replace.d~
COMPILE ~Mod/Dialogue/Interjections.d~

NOTE: Be very, very careful in attributing correct numbers to each interjection, or your game will quickly become a mess.

3) Party members: cre files.

Very easy: create a .chr file, open it in NI. You have three fields to change: death variable(script name), override script, and dialogue file. With "script name", just edit your NPC name with your prefix in. With NPC's override script and NPC's dialogue file, right-click on these fields, choose "edit as string", double-click, edit the necessary value and save. Note that your NPC will have only one dialogue file.



I'll try to add more to it, if I remember anything else useful. But that's it for the time being.

Happy modding!

 

With Quick-Reply you can write a post when viewing a topic without loading a new page. You can still use bulletin board code and smileys as you would in a normal post.

Warning: this topic has not been posted in for at least 120 days.
Unless you're sure you want to reply, please consider starting a new topic.

Name: Email:
Verification:
Type the letters shown in the picture
Listen to the letters / Request another image
Type the letters shown in the picture:
What color is grass?:
What is the seventh word in this sentence?:
What is five minus two (use the full word)?: