Author Topic: How to change an NPC's dialogue file during the game  (Read 4097 times)

Offline Kulyok

  • Global Moderator
  • Planewalker
  • *****
  • Posts: 6253
  • Gender: Female
  • The perfect moment is now.
How to change an NPC's dialogue file during the game
« on: February 25, 2009, 12:12:16 PM »
http://forums.pocketplane.net/index.php/topic,26316

In short, can I set(change) NPC's dialogue file during the game, via his .baf file or something?

Offline GeN1e

  • Planewalker
  • *****
  • Posts: 267
  • Gender: Male
Re: How to change an NPC's dialogue file during the game
« Reply #1 on: February 25, 2009, 02:13:37 PM »
SetDialog("dlgname")?

Offline jastey

  • Global Moderator
  • Planewalker
  • *****
  • Posts: 1524
  • Gender: Female
Re: How to change an NPC's dialogue file during the game
« Reply #2 on: February 25, 2009, 03:36:38 PM »
Gods. I will never, ever complain about the restrictions of the BG1 engine (remind me).

I know that in BGII, the dialogue file can be changed, yes. Weimer's Solaufein does it for the banters in ToB, for example: switches back the BioWare NPC banter files for the dialogue with Solaufein to their SoA-dialog file. The syntax could be what GeN1e said, I would have to check.

Offline cmorgan

  • Planewalker
  • *****
  • Posts: 1424
  • Gender: Male
  • Searcher of Bugs
Re: How to change an NPC's dialogue file during the game
« Reply #3 on: February 25, 2009, 04:06:03 PM »
I have seen this used somewhere (and have speculated that it was a good way around some compatability hassles, though in the posts about this idea I think JCompton pointed out I was doing alot of extra garbage playing the "shell game" with swapping around dialog files this way).

(This is old news to Kulyok, but for people who are not as versed in scripting/closing variables in dialog, the breakdown and fleshing out of this idea goes like this:


138 SetDialog(S:DialogFile*)
138 SetDialogue(S:DialogFile*)


in the npc .baf =

IF
    RealGlobalTimerExpired("myTimer","GLOBAL")
    InParty("myNPC")
    !Statecheck("myNPC",CD_STATE_NOTVALID)
    InParty(Player1)
    See(Player1)
    !Statecheck(Player1,CD_STATE_NOTVALID)
    Global("myGlovbalVariable","GLOBAL",1)
THEN RESPONSE #100
    ActionOverride("myNPC",SetDialog("C-NEWINT"))
    Global("myGlobalVariable","GLOBAL",2)
    Wait(1)
    StartDialogNoSet(Player1)
END

in the  .d =

/* reset the [original or joined] dialog file at the end of the state when you advance the variable and set timers */
IF ~Global("myGlobalVariable","GLOBAL",2)~ myNewState
  SAY ~[MYNPC] Hey, this line is coming out of a new dialog file that contains only stuff from myMod, thus is not messed with by anyone modifying the original dialog~
  IF ~~ THEN DO ~ActionOverride("myNPC",SetDialog("myNPCJ")) Global("myGlobalVariable","GLOBAL",3) RealSetGlobalTimer("myTimer","GLOBAL",400)~ EXIT
END

Only minor problems -

while lots of stuff sets dialog to default using this kind of scripting, not much out there plays this game, so it is theoretical not "tested exensively in the field" I wuz wrong. It is used. If something hangs up on the script running, you end up with a stutter (trying to clear a dialog set on the original dialog file while when the .cre in question is assigned your mod's dialog file). I think if you are looking at doing something like this, you are probably safest using a form of Kulyok's IWD and similar work, scripting using cutscene mode and being aggressive with checks to revert dialog files. I don't know about using separated .bcs blocks under those conditions.

EDIT: serves me right for posting before running the search of existing NPC's code -.

Amber does this, BTL does this, and Chloe does this, Edwin Flirtpack does this, Imoen v12 does this, Kiara-Zaiya does this (once), LongerRoad_v1.5.1 does it once, TSv611 does it once for Yoshimo, and Weimer-SolaufeinMod-v103 does it extensively.

Sample code from Weimer:

Code: [Select]
///////////////////////////////////////////////////////////////////////
// If we're in ToB, quickly change back to using the old dialogue
// files.
///////////////////////////////////////////////////////////////////////
IF
  Global("SolaGoingToBanter","GLOBAL",1)
  GlobalGT("Chapter","GLOBAL",7)        // >7 --> in ToB
  CombatCounter(0)
THEN
  RESPONSE #100
    StartCutSceneMode()
    SetGlobal("SolaPickingBanterTarget","GLOBAL",0)
    SetGlobal("SolaGoingToBanter","GLOBAL",0)
    ActionOverride("Aerie",SetDialogue("BAERIE"))
    ActionOverride("Anomen",SetDialogue("BANOMEN"))
    ActionOverride("Cernd",SetDialogue("BCERND"))
    ActionOverride("Edwin",SetDialogue("BEDWIN"))
    ActionOverride("HaerDalis",SetDialogue("BHAERDA"))
    ActionOverride("Imoen2",SetDialogue("IMOEN2J"))
    ActionOverride("Jaheira",SetDialogue("BJAHEIR"))
    ActionOverride("Jan",SetDialogue("BJAN"))
    ActionOverride("Keldorn",SetDialogue("BKELDOR"))
    ActionOverride("Korgan",SetDialogue("BKORGAN"))
    ActionOverride("Mazzy",SetDialogue("BMAZZY"))
    ActionOverride("Minsc",SetDialogue("BMINSC"))
    ActionOverride("Nalia",SetDialogue("BNALIA"))
    ActionOverride("Valygar",SetDialogue("BVALYGA"))
    ActionOverride("Viconia",SetDialogue("BVICONI"))
    // Sarevok needs no change
    RealSetGlobalTimer("SolaBanter","GLOBAL",6400)
    SetGlobal("Sola_Try_Aerie","GLOBAL",0)
    SetGlobal("Sola_Try_Anomen","GLOBAL",0)
    SetGlobal("Sola_Try_Cernd","GLOBAL",0)
    SetGlobal("Sola_Try_Edwin","GLOBAL",0)
    SetGlobal("Sola_Try_HD","GLOBAL",0)
    SetGlobal("Sola_Try_Imoen","GLOBAL",0)
    SetGlobal("Sola_Try_Jan","GLOBAL",0)
    SetGlobal("Sola_Try_Jaheira","GLOBAL",0)
    SetGlobal("Sola_Try_Keldorn","GLOBAL",0)
    SetGlobal("Sola_Try_Korgan","GLOBAL",0)
    SetGlobal("Sola_Try_Mazzy","GLOBAL",0)
    SetGlobal("Sola_Try_Minsc","GLOBAL",0)
    SetGlobal("Sola_Try_Nalia","GLOBAL",0)
    SetGlobal("Sola_Try_Valygar","GLOBAL",0)
    SetGlobal("Sola_Try_Viconia","GLOBAL",0)
    SetGlobal("Sola_Try_Sarevok","GLOBAL",0)
    StartDialogueNoSet(Player1)
END

///////////////////////////////////////////////////////////////////////
// Otherwise just banter
///////////////////////////////////////////////////////////////////////
IF
  Global("SolaGoingToBanter","GLOBAL",1)
  !GlobalGT("Chapter","GLOBAL",7)        // >7 --> in ToB
  CombatCounter(0)
THEN
  RESPONSE #100
    StartCutSceneMode()
    SetGlobal("SolaPickingBanterTarget","GLOBAL",0)
    SetGlobal("SolaGoingToBanter","GLOBAL",0)
    RealSetGlobalTimer("SolaBanter","GLOBAL",6400)
    SetGlobal("Sola_Try_Aerie","GLOBAL",0)
    SetGlobal("Sola_Try_Anomen","GLOBAL",0)
    SetGlobal("Sola_Try_Cernd","GLOBAL",0)
    SetGlobal("Sola_Try_Edwin","GLOBAL",0)
    SetGlobal("Sola_Try_HD","GLOBAL",0)
    SetGlobal("Sola_Try_Imoen","GLOBAL",0)
    SetGlobal("Sola_Try_Jan","GLOBAL",0)
    SetGlobal("Sola_Try_Jaheira","GLOBAL",0)
    SetGlobal("Sola_Try_Keldorn","GLOBAL",0)
    SetGlobal("Sola_Try_Korgan","GLOBAL",0)
    SetGlobal("Sola_Try_Mazzy","GLOBAL",0)
    SetGlobal("Sola_Try_Minsc","GLOBAL",0)
    SetGlobal("Sola_Try_Nalia","GLOBAL",0)
    SetGlobal("Sola_Try_Valygar","GLOBAL",0)
    SetGlobal("Sola_Try_Viconia","GLOBAL",0)
    SetGlobal("Sola_Try_Sarevok","GLOBAL",0)
    StartDialogueNoSet(Player1)
END

///////////////////////////////////////////////////////////////////////
// Restore those TOB dialogue files
///////////////////////////////////////////////////////////////////////
IF
  Global("SolaDoneBanter","GLOBAL",1)
  GlobalGT("Chapter","GLOBAL",7)        // >7 --> in ToB
THEN
  RESPONSE #100
    SetGlobal("SolaDoneBanter","GLOBAL",0)
    ActionOverride("Aerie",SetDialogue("AERIE25J"))
    ActionOverride("Anomen",SetDialogue("ANOME25J"))
    ActionOverride("Cernd",SetDialogue("CERND25J"))
    ActionOverride("Edwin",SetDialogue("EDWIN25J"))
    ActionOverride("HaerDalis",SetDialogue("HAERD25J"))
    ActionOverride("Imoen2",SetDialogue("IMOEN25J"))
    ActionOverride("Jaheira",SetDialogue("JAHEI25J"))
    ActionOverride("Jan",SetDialogue("JAN25J"))
    ActionOverride("Keldorn",SetDialogue("KELDO25J"))
    ActionOverride("Korgan",SetDialogue("KORGA25J"))
    ActionOverride("Mazzy",SetDialogue("MAZZY25J"))
    ActionOverride("Minsc",SetDialogue("MINSC25J"))
    ActionOverride("Nalia",SetDialogue("NALIA25J"))
    ActionOverride("Valygar",SetDialogue("VALYG25J"))
    ActionOverride("Viconia",SetDialogue("VICON25J"))
    EndCutSceneMode()
    // Sarevok needs no change
END

IF
  Global("SolaDoneBanter","GLOBAL",1)
  !GlobalGT("Chapter","GLOBAL",7)        // <=7 --> in SoA
THEN
  RESPONSE #100
    SetGlobal("SolaDoneBanter","GLOBAL",0)
    EndCutSceneMode()
END


Looks like he solved the possible problems with those     StartCutSceneMode() || EndCutSceneMode() calls. Noone else is as detailed - but Chloe starts the dialog from the file directly for the NPC:

Code: [Select]
IF
   OR(2)
     Global("InAbagailQuestCR","GLOBAL",2)
     Global("InAbagailQuestCR","GLOBAL",3)
   AreaCheck("AR0528")
THEN
   RESPONSE #100
   SetGlobal("InAbagailQuestCR","GLOBAL",4)
   ActionOverride("AbbyHuCR",SetDialog("AbbyCR"))
   ActionOverride("AbbyVaCR",SetDialog("AbbyCR"))
   Wait(1)
   ActionOverride("AbbyHuCR",FaceObject(Player1))
   ActionOverride("AbbyVaCR",FaceObject(Player1))
   Wait(2)
   ActionOverride("AbbyHuCR",StartDialog("AbbyCR",Player1))
   ActionOverride("AbbyVaCR",StartDialog("AbbyCR",Player1))
END
with Wait(#) to allow the game to process, I guess.


Amber uses the dialog reset within dialog successfully, too:

Code: [Select]
// Amber's kidnapping - quest. Dialogs for the Slaver, Corin, Lorraine, Guard captain, Bathing guard, Cook, Maid, Demon, Gabriel, Nyphs, Ymmyrt, Soul Machine and Lorraine's son.

BEGIN ~M#KCUT~
IF ~True()~ THEN BEGIN Intro
  SAY @3109 /* @3109 = ~Ah, there you are, tiefling. I have been looking for you.~ */
  IF ~RandomNum(4,1)~ THEN DO ~ActionOverride("M#Amber",SetDialog("m#ambern"))~ GOTO Continuation1
  IF ~RandomNum(4,2)~ THEN DO ~ActionOverride("M#Amber",SetDialog("m#ambern"))~ GOTO Continuation2
  IF ~RandomNum(4,3)~ THEN DO ~ActionOverride("M#Amber",SetDialog("m#ambern"))~ GOTO Continuation3
  IF ~RandomNum(4,4)~ THEN DO ~ActionOverride("M#Amber",SetDialog("m#ambern"))~ GOTO Continuation4
END


a .bcs call to make absolutely sure the correct dialog file is set for her kidnapping:
Code: [Select]
// Amber's Kidnapping Quest
IF
Global("M#AmberKidnap","GLOBAL",8)
AreaCheck("m#ar01")
Detect(Player1)
THEN
RESPONSE #100
Wait(1)
FaceObject(Player1)
DisplayStringHead(Myself,@77)
Wait(2)
SetDialog("m#amberp")
PlaySong(999997)
Dialog(Player1)
END

It looks like the most modern and extensive source is Amber, as she shifts between m#amberj, m#ambern, etc. within both .baf and .d.
« Last Edit: February 25, 2009, 04:28:02 PM by cmorgan »

Offline GeN1e

  • Planewalker
  • *****
  • Posts: 267
  • Gender: Male
Re: How to change an NPC's dialogue file during the game
« Reply #4 on: February 25, 2009, 07:02:05 PM »
Quote
in the npc .baf =

IF
    RealGlobalTimerExpired("myTimer","GLOBAL")
    InParty("myNPC")
    !Statecheck("myNPC",CD_STATE_NOTVALID)
    InParty(Player1)
    See(Player1)
    !Statecheck(Player1,CD_STATE_NOTVALID)
    Global("myGlovbalVariable","GLOBAL",1)
THEN RESPONSE #100
    ____ActionOverride("myNPC",SetDialog("C-NEWINT"))____
    Global("myGlobalVariable","GLOBAL",2)
    Wait(1)
    ____StartDialogNoSet(Player1)____
END

in the  .d =

/* reset the [original or joined] dialog file at the end of the state when you advance the variable and set timers */
IF ~Global("myGlobalVariable","GLOBAL",2)~ myNewState
  SAY ~[MYNPC] Hey, this line is coming out of a new dialog file that contains only stuff from myMod, thus is not messed with by anyone modifying the original dialog~
  IF ~~ THEN DO ~____ActionOverride("myNPC",SetDialog("myNPCJ"))____ Global("myGlobalVariable","GLOBAL",3) RealSetGlobalTimer("myTimer","GLOBAL",400)~ EXIT
END
StartDialog("C-NEWINT",MyselfOrSomeoneElse) takes care of the switching hassle.
« Last Edit: February 25, 2009, 07:04:02 PM by GeN1e »

Offline cmorgan

  • Planewalker
  • *****
  • Posts: 1424
  • Gender: Male
  • Searcher of Bugs
Re: How to change an NPC's dialogue file during the game
« Reply #5 on: February 25, 2009, 09:39:47 PM »
yep - that looks a bit more efficient. I was wondering why the Chloe was formed that way.

Offline Kulyok

  • Global Moderator
  • Planewalker
  • *****
  • Posts: 6253
  • Gender: Female
  • The perfect moment is now.
Re: How to change an NPC's dialogue file during the game
« Reply #6 on: February 26, 2009, 12:27:45 AM »
That's really cool! Thank you very much, folks - I'll try to implement and test these things for the next version of IWD NPC. Let's hope the engine won't break. :)

Offline Kulyok

  • Global Moderator
  • Planewalker
  • *****
  • Posts: 6253
  • Gender: Female
  • The perfect moment is now.
Re: How to change an NPC's dialogue file during the game
« Reply #7 on: April 19, 2009, 04:58:55 AM »
... and it's me again.

Thanks to your good advice, it worked - when I StartDialog("MyDialog",SomeNPC), the game no longer crashes.

But - unfortunately, we have interjections, as well. When the Evil Guy says "Myahahaha, I will kill you all!" and my NPC is about to say "Will not!"(and we suddenly find out that our NPC's dialogue file is empty!) - the game crashes.

Is there a script-y way to check that our dialogue file exists, maybe? Something like

If "NPC's dialogue file" <> "O#TERI"?

... because otherwise I'm afraid that I am royally screwed.

Offline Kulyok

  • Global Moderator
  • Planewalker
  • *****
  • Posts: 6253
  • Gender: Female
  • The perfect moment is now.
Re: How to change an NPC's dialogue file during the game
« Reply #8 on: April 19, 2009, 05:31:06 AM »
A thought:

Maybe I should just run a timer? Every two minutes, no matter what, each character's dialogue file will be set to normal(i.e. O#TERI for Teri, etc).

Or every five minutes?
One minute?

Offline Kulyok

  • Global Moderator
  • Planewalker
  • *****
  • Posts: 6253
  • Gender: Female
  • The perfect moment is now.
Re: How to change an NPC's dialogue file during the game
« Reply #9 on: April 19, 2009, 05:40:23 AM »
Damn. The game sucks - it has no real timers.

Offline Kulyok

  • Global Moderator
  • Planewalker
  • *****
  • Posts: 6253
  • Gender: Female
  • The perfect moment is now.
Re: How to change an NPC's dialogue file during the game
« Reply #10 on: April 19, 2009, 05:41:13 AM »
Oh! A "K" hotkey! Heh-heh!



EDIT: Aaaand - yes, solution found. Hotkeys + StartDialog (in PC-NPC, NPC-NPC banters) work nicely.

 

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)?: