Jump to content

Improving on INTERJECT_COPY_TRANS3 - passbacks only if necessary


Recommended Posts

A large part of NPC modding is the interjections into existing conversations, and WEIDU has a lot of technology to help with it. I recently wrote some functions to supplement that technology a bit; this series of posts is an explanation.

In this first post I'll explain current best practice for these interjections. (Much of this material is also covered in a very informative series of posts by Kaeloree at Spellhold Studios.) In the second post I'll say what I think is wrong with it; in the third post I'll suggest a way to improve on it.

Basic interjections work like this. An existing dialog block might look like:

IF ~~ THEN BEGIN 14
SAY ~Hello, O great adventurer.~
IF ~~ THEN REPLY ~Finally, someone recognises my greatness!~ GOTO 15
IF ~~ THEN REPLY ~Aw, shucks, I'm not so great as all that.~ GOTO 16
END

A simple interjection, most straightforwardly coded with INTERJECT_COPY_TRANS, changes it to something like

IF ~~ THEN BEGIN 14
SAY ~Hello, O great adventurer.~
IF ~~ THEN REPLY ~Finally, someone recognises my greatness!~ GOTO 15
IF ~~ THEN REPLY ~Aw, shucks, I'm not so great as all that.~ GOTO 16
IF ~InParty("imoen2")~ THEN EXTERN imoen2 17
END
<imoen block>
IF ~~ THEN BEGIN 17
SAY ~Hey, you'll give <CHARNAME> delusions of grandeur!~
IF ~~ THEN REPLY ~Finally, someone recognises my greatness!~ EXTERN original_npc 15
IF ~~ THEN REPLY ~Aw, shucks, I'm not so great as all that.~ EXTERN original_npc 16
END

In other words, if Imoen is present then the dialog skips to her interjection; the player then gets offered the original reply options from her dialog.

That works fine *unless* there are DO blocks in the original. Suppose, say, that the original block was:

IF ~~ THEN BEGIN 14
SAY ~Hello, O great adventurer. Have some gold as a token of your magnificence.~
IF ~~ THEN REPLY ~Finally, someone recognises my greatness!~ DO ~GivePartyGold(500)~ GOTO 15
IF ~~ THEN REPLY ~Aw, shucks, I'm not so great as all that.~ DO ~GivePartyGold(500)~ GOTO 16
END

If those blocks move to Imoen, then it will be her, not the NPC, who tries to give the gold to the party, and that doesn't work - she doesn't have the gold in her inventory. (It would be even more dramatic if there was an Enemy() command!) One solution - this is what INTERJECT_COPY_TRANS2 does - is to move the GivePartyGold command to the original Imoen reply, as in:

 

IF ~~ THEN BEGIN 14
SAY ~Hello, O great adventurer.  Have some gold as a token of your magnificence.~
IF ~~ THEN REPLY ~Finally, someone recognises my greatness!~ DO ~GivePartyGold(500)~ GOTO 15
IF ~~ THEN REPLY ~Aw, shucks, I'm not so great as all that.~ DO ~GivePartyGold(500)~ GOTO 16
IF ~InParty("imoen2")~ THEN DO ~GivePartyGold(500)~ EXTERN imoen2 17
END

But modders are generally advised against this, as it only works if all the DO actions are the same. Suppose instead that the original block looks like

IF ~~ THEN BEGIN 14
SAY ~Hello, O great adventurer. Have some gold as a token of your magnificence.~
IF ~~ THEN REPLY ~Finally, someone recognises my greatness!~ DO ~GivePartyGold(500)~ GOTO 15
IF ~~ THEN REPLY ~Aw, shucks, I'm not so great as all that. Your need is greater than mine - keep the gold.~ GOTO 16
END

Now there's no way to move 'the' DO command to Imoen's interjection, because there's no single DO command.

Because of this problem, current best practice is to include a 'passback'  - a block in the original NPC's dialog that the original replies move to. With a passback, the original dialog gets modified to:

IF ~~ THEN BEGIN 14
SAY ~Hello, O great adventurer. Have some gold as a token of your magnificence.~
IF ~~ THEN REPLY ~Finally, someone recognises my greatness!~ DO ~GivePartyGold(500)~ GOTO 15
IF ~~ THEN REPLY ~Aw, shucks, I'm not so great as all that. Your need is greater than mine - keep the gold.~ GOTO 16
IF ~~ THEN GOTO 99
END
IF ~~ THEN BEGIN 99
SAY ~Yes, you really are great.~
IF ~~ THEN REPLY ~Finally, someone recognises my greatness!~ DO ~GivePartyGold(500)~ GOTO 15
IF ~~ THEN REPLY ~Aw, shucks, I'm not so great as all that. Your need is greater than mine - keep the gold.~ GOTO 16
END

In the original block (block 14) the original replies never have a chance to fire - the dialog automatically jumps to block 99. After an extra line of dialog, the original replies are there.

Now when Imoen's interjection is added, we get

IF ~~ THEN BEGIN 14
SAY ~Hello, O great adventurer. Have some gold as a token of your magnificence.~
IF ~~ THEN REPLY ~Finally, someone recognises my greatness!~ DO ~GivePartyGold(500)~ GOTO 15
IF ~~ THEN REPLY ~Aw, shucks, I'm not so great as all that. Your need is greater than mine - keep the gold.~ GOTO 16
IF ~~ THEN GOTO 99
IF ~InParty("imoen2")~ THEN EXTERN imoen2 17
END
	IF ~~ THEN BEGIN 99
SAY ~Yes, you really are great.~
IF ~~ THEN REPLY ~Finally, someone recognises my greatness!~ DO ~GivePartyGold(500)~ GOTO 15
IF ~~ THEN REPLY ~Aw, shucks, I'm not so great as all that. Your need is greater than mine - keep the gold.~ GOTO 16
END
<imoen block>
IF ~~ THEN BEGIN 17
SAY ~Hey, you'll give <CHARNAME> delusions of grandeur!~
IF ~~ THEN REPLY ~Finally, someone recognises my greatness!~ DO ~GivePartyGold(500)~ EXTERN original_npc 15
IF ~~ THEN REPLY ~Aw, shucks, I'm not so great as all that. Your need is greater than mine - keep the gold.~ EXTERN original_npc 16
IF ~~ THEN GOTO 99
END


The transitions are copied to Imoen's block, and again the original replies never have a chance to fire. Instead we're routed back to the passback. The original replies are then offered to the player, and because they're being offered by the original NPC, there's no problem with actions being associated to the wrong creature.

All this normally gets implemented via the INTERJECT_COPY_TRANS3 command in WEIDU. Here's an example from BG1NPC (bg1npc/phase2/dlg/x#ict3.d):

/* Davaeorn */
/* passback supplied */
I_C_T3 ~tutu_varDAVAEO~ 0 X#DAVAEO0
== ~YESLIJ~ IF ~InParty("yeslick") InMyArea("yeslick") !StateCheck("yeslick",CD_STATE_NOTVALID)~ THEN @206
== ~DAVAEO~ IF ~InParty("yeslick") InMyArea("yeslick") !StateCheck("yeslick",CD_STATE_NOTVALID)~ THEN @207
== ~DYNAHJ~ IF ~InParty("dynaheir") InMyArea("dynaheir") !StateCheck("dynaheir",CD_STATE_NOTVALID)~ THEN @208
== ~IMOENJ~ IF ~InParty("imoen") InMyArea("imoen") !StateCheck("imoen",CD_STATE_NOTVALID) !Class("imoen",MAGE_ALL)~ THEN @209
== ~CORANJ~ IF ~InParty("coran") InMyArea("coran") !StateCheck("coran",CD_STATE_NOTVALID)~ THEN @210
== ~SHARTJ~ IF ~InParty("sharteel") InMyArea("sharteel") !StateCheck("sharteel",CD_STATE_NOTVALID)~ THEN @211
== ~FALDOJ~ IF ~InParty("faldorn") InMyArea("faldorn") !StateCheck("faldorn",CD_STATE_NOTVALID)~ THEN @212
== ~DAVAEO~ IF ~InParty("faldorn") InMyArea("faldorn") !StateCheck("faldorn",CD_STATE_NOTVALID)~ THEN @213
== ~KIVANJ~ IF ~InParty("kivan") InMyArea("kivan") !StateCheck("kivan",CD_STATE_NOTVALID)~ THEN @214
== ~VICONJ~ IF ~InParty("viconia") InMyArea("viconia") !StateCheck("viconia",CD_STATE_NOTVALID)~ THEN @215
== ~DAVAEO~ @216
END

The last line is the passback. All the other lines are the various interjections by party members. (For readability I've removed the various bits of BG1NPC code that localise this to BGT/BG1TUTU/BGEE.)

Link to comment

The passback solution is elegant and reliable: so what's wrong with it? 

One problem is that the code it generates is very cluttered. You can see this in the Imoen example in the last post: there are extra REPLYs in Imoen's block and in block 14 that are guaranteed never to fire. In realistic code it gets much, much worse than that - if you actually implement that Davaeorn interject (e.g. by installing BG1NPC) and then do 'weidu davaeo.dlg --transitive' you'll see what I mean. There are many copies of each block, and long strings of reply options that are just along for the ride, and if you try to make sense of the dialog block, it's almost impossible to understand the logic. But this doesn't matter that much: you can't see that tangle in-game, it doesn't slow things down, and trying to modify existing interjections in another mod is an edge case at best.

The real problem is that the passback blocks upset the flow of the dialog. Look at Davaeorn again: in the unmodded game, his line to you is the marvellously dismissive


Why have you come? Is it to steal my riches or perhaps you seek to righteously punish me for my affront to your morality? It matters little, for you will do neither. Before I dispose of you in some horribly gruesome manner, perhaps I should introduce myself. I am known as Davaeorn. I would ask you for your names, but I care little to become acquainted with the dead.


after which he goes hostile and attacks without any further comment.

In BG1NPC, if you encounter Davaeorn without any NPCs present, this becomes


Why have you come? Is it to steal my riches or perhaps you seek to righteously punish me for my affront to your morality? It matters little, for you will do neither. Before I dispose of you in some horribly gruesome manner, perhaps I should introduce myself. I am known as Davaeorn. I would ask you for your names, but I care little to become acquainted with the dead.

Now that we have been introduced, it is time for you to die!


The second line is the passback, which you also get following any interjections from party NPCs.

To my ear, that reads much less well. And in general, I think it's hard to write passbacks that don't just clutter and slow the flow of dialog (especially since you're having to add them in to dialogs which weren't originally written to facilitate them.)

What's the alternative? Well, as it happens Davaeorn doesn't need a passback at all: there's only one DO command in his original replies - ~Enemy()~ and that can be moved, INTERJECT_COPY_TRANS2 style, to the NPC interjections. Even if that wasn't the case, there's no need for a passback if there are no NPCs present, and there's no need for a passback if the last interjection comes from Yeslick or Faldorn, since - as you can see from the block I pasted above - in those cases Davaeorn has a reply to that NPC already.

But of course coding that gets very cumbersome and quite vulnerable to possible changes made by other mods (say, if someone else added a 'talk Davaeorn down' mod). The solution is to automate it: I'll explain how that works in the next post.

Link to comment

The function 'compile_with_ict_handling' is intended to address these issues. It has one argument, 'dialog', which should be the full name and path of a dialog file containing I_C_T3 (and I_C_T4) blocks.

When it runs, it goes through each ICT block and modifies the dialog to implement the interjections. The passback is only included if it's needed, which is to say: if there are multiple REPLYs to the original block with different code in (or if any block uses StartStore(), which causes trouble if it's moved). And the passback is only used in interjection chains where it's needed (i.e., when the original NPC doesn't get the last word in any case). If a passback is needed but there isn't one already, a blank one is added, i.e., the NPC replies but doesn't say anything. (That's a bit untidy, but the alternative would be breaking the logic of the dialog.) As a bonus, the code created is much tidier, without extra block copies and unused replies.

Once all the I_C_Tx blocks are implemented, any remaining dialog is COMPILEd normally. (There are limitations here: if there are cross-references between I_C_Tx and non-I_C_Tx blocks, the code will fail.)

I've implemented this in a fork of BG1NPC, available here. The function is contained in "lib/lib_interject.tpa"; it also requires some functions in "lib/alter_dlg.tpa". The only change in BG1NPC's code itself (other than turning on the AUTO_EVAL_STRINGS setting) is a replacement, in bg1npc.tp2, of

COMPILE EVALUATE_BUFFER ~bg1npc/Phase2/dlg/X#ICT3.D~ 

with

WITH_TRA "bg1npc\tra\english\x#ict3.tra" "bg1npc\tra\%LANGUAGE%\x#ict3.tra" BEGIN
     LAF compile_with_ict_handling STR_VAR dialog="bg1npc/Phase2/dlg/x#ict3.d" END
END

(I have to give it the dialog file explicitly, since my code doesn't interact with AUTO_TRA.)

Thoughts and feedback very welcome.
 

Link to comment

This means the passback line would be spared if no other mod added differently triggered transactions, but would play out like it is now if the line would be needed because of the transactions? That sounds very cool. The main reason I am using I_C_T(3) with passback as a standard is because I can't be sure another mod didn't add more transactions to the dialogue state I am interjecting to. With this function, the added passback would just be a savety measure in case that's the case.

For passback line the function just takes the last line with the original NPC talking?

What exactly does this do, what is changed in the dialogue, do you mean the dlg?

17 hours ago, DavidW said:

goes through each ICT block and modifies the dialog to implement the interjections

I do not agree that an empty dialogue box wouldn't disturb the flow of the dialogue, though. For me, an empty box would more look like a bug or "mod added".

All in all this sounds like a really good thing to get rid of at least some of the passback lines. :party:

Link to comment

Yes, I mean the dlg. And passback line is the last line of the ICT3, provided it’s spoken by the original NPC with no conditions (I’m following bg1npc conventions here).

As for an empty passback: yes, I agree, it’s ugly and breaks the flow. But in the situations where I use it, the alternative is a logic error that can break the game, so I think it’s the least worst option. (It’s only going to come up if the function gets handed an ICT3 that should have had a passback but doesn’t.)

Link to comment

Ah, I didn't catch you are explicitely talking about unconditioned passback lines (because I obviously didn't look at the example thoroughly enough).

BG1NPC had the problem of combining lines for several NPCs where there is no logixal trigger to account for one of them present. Usually, in a mod it is one NPC and then the passback line bears the trigger of this NPC beging present. Since some of my NPCs like to babble a comment into CHARNAME's ear which the original game character isn't even supposed to hear, lest alone comment on it, would it be possible to include the last line spoken by the original DLG as a passback line in your function, no matter the conditions?

I can provide examples if you want later when I am back at my computer.

Link to comment

Hi @DavidW, for BG1NPC I used the function in the following way:

include the function definition in the ALWAYS block (inside "bg1npc_always.tpa"):

INCLUDE "bg1npc/lib/lib_interject.tpa"
INCLUDE "bg1npc/lib/alter_dlg.tpa"

Then calling the function to compile the files with the multiple interjections "x#ict3.d" (function call in "bg1npc_phase2.tpa"):

  WITH_TRA "bg1npc\tra\english\x#ict3.tra" "bg1npc\tra\%LANGUAGE%\x#ict3.tra" BEGIN
     LAF compile_with_ict_handling STR_VAR dialog="bg1npc/Phase2/dlg/X#ICT3.D" END
  END

When looking at the game files after installing the mod (component "Quest, Banters and Interjections"), there are some interjections missing in the game. For example, Branwen and Quayle's interjection into GAZIB.dlg (tested in BGT). This is what the I_C_T3 inside the "x#ict3.d" looks like:


/* Great Gazib, the */
/* passback not required - trans action is CreateCreature() */
I_C_T3 ~%tutu_var%GAZIB~ 1 X#GAZIB1
== ~%BRANWEN_JOINED%~ IF ~InParty("branwen") InMyArea("branwen") !StateCheck("branwen",CD_STATE_NOTVALID)~ THEN @699
== ~%QUAYLE_JOINED%~ IF ~InParty("quayle") InMyArea("quayle") !StateCheck("quayle",CD_STATE_NOTVALID)~ THEN @700
END

Compiled using the function as described above, the GAZIB.dlg looks like this - no interjections are added to state 1:

Spoiler

// creator  : D:\NearInfinity-20180615\NearInfinity.jar (v2.1-20180615)
// game     : D:\BGT
// resource : GAZIB.DLG
// source   : Override\GAZIB.DLG
// dialog   : dialog.tlk
// dialogF  : (none)

BEGIN ~GAZIB~

IF ~  NumberOfTimesTalkedTo(0)
~ THEN BEGIN 0 // from:
  SAY #79830 /* ~Hi, come well and welcome! You have stumbled upon The Great Gazib Show, starring yours truly, the Great Gazib!!! Allow me to introduce the Amazing Oopah, the world's only exploding ogre!~ */
  IF ~~ THEN DO ~CreateCreature("OOPAH",[1282.3222],1)
~ EXIT
  IF ~  Global("X#GarGaz","GLOBAL",0)
InParty("garrick")
InMyArea("garrick")
!StateCheck("garrick",CD_STATE_NOTVALID)
~ THEN DO ~SetGlobal("X#GarGaz","GLOBAL",1)
~ EXTERN ~GARRIJ~ 71
END

IF ~  NumberOfTimesTalkedTo(1)
Dead("Oopah")
~ THEN BEGIN 1 // from:
  SAY #79831 /* ~Fun for the whole family! Now, let's try that crowd-pleaser one more time.~ */
  IF ~~ THEN DO ~CreateCreature("OOPAH",[1282.3222],1)
~ EXIT
END

IF ~  GlobalGT("SPRITE_IS_DEADOopah","GLOBAL",1)
~ THEN BEGIN 2 // from:
  SAY #79832 /* ~You're either a die-hard fan or a sadist, friend... (No, Oopah, just one more, one last one, then you can go back to the tent... Oopah, put the weapon down... Oopah?) AAaeee!~ */
  IF ~~ THEN DO ~CreateCreature("OOPAH2",[1282.3222],1)
EscapeAreaDestroy(90)
~ EXIT
  IF ~  Global("X#VicGaz","GLOBAL",0)
InParty("viconia")
InMyArea("viconia")
!StateCheck("viconia",CD_STATE_NOTVALID)
~ THEN DO ~SetGlobal("X#VicGaz","GLOBAL",1)
~ EXTERN ~VICONIJ~ 292
END

IF ~~ THEN BEGIN 3 // from:
  SAY #119010 /* ~Step right up!~ */
  IF ~~ THEN DO ~CreateCreature("OOPAH",[1282.3222],1)
~ EXIT
END

IF ~~ THEN BEGIN 4 // from:
  SAY #89489 /* ~Noooo!~ */
  IF ~~ THEN DO ~CreateCreature("OOPAH2",[1282.3222],1)
EscapeAreaDestroy(90)
~ EXIT
END

 

If I disable the function and compile the file directly, the GAZIB.dlg looks like this, now the interjections are added to state 1:

Spoiler

// creator  : D:\NearInfinity-20180615\NearInfinity.jar (v2.1-20180615)
// game     : D:\BGT
// resource : GAZIB.DLG
// source   : Override\GAZIB.DLG
// dialog   : dialog.tlk
// dialogF  : (none)

BEGIN ~GAZIB~

IF ~  NumberOfTimesTalkedTo(0)
~ THEN BEGIN 0 // from:
  SAY #79830 /* ~Hi, come well and welcome! You have stumbled upon The Great Gazib Show, starring yours truly, the Great Gazib!!! Allow me to introduce the Amazing Oopah, the world's only exploding ogre!~ */
  IF ~~ THEN DO ~CreateCreature("OOPAH",[1282.3222],1)
~ EXIT
  IF ~Global("X#GarGaz","GLOBAL",0)
InParty("garrick")
InMyArea("garrick")
!StateCheck("garrick",CD_STATE_NOTVALID)
~ THEN DO ~SetGlobal("X#GarGaz","GLOBAL",1)~ EXTERN ~GARRIJ~ 71
END

IF ~  NumberOfTimesTalkedTo(1)
Dead("Oopah")
~ THEN BEGIN 1 // from:
  SAY #79831 /* ~Fun for the whole family! Now, let's try that crowd-pleaser one more time.~ */
  IF ~~ THEN DO ~CreateCreature("OOPAH",[1282.3222],1)
~ EXIT
  IF ~Global("X#GAZIB1","GLOBAL",0)
InParty("quayle")
InMyArea("quayle")
!StateCheck("quayle",CD_STATE_NOTVALID)
~ THEN DO ~SetGlobal("X#GAZIB1","GLOBAL",1)~ EXTERN ~QUAYLJ~ 52
  IF ~Global("X#GAZIB1","GLOBAL",0)
InParty("branwen")
InMyArea("branwen")
!StateCheck("branwen",CD_STATE_NOTVALID)
~ THEN DO ~SetGlobal("X#GAZIB1","GLOBAL",1)~ EXTERN ~BRANWJ~ 102
END

IF ~  GlobalGT("SPRITE_IS_DEADOopah","GLOBAL",1)
~ THEN BEGIN 2 // from:
  SAY #79832 /* ~You're either a die-hard fan or a sadist, friend... (No, Oopah, just one more, one last one, then you can go back to the tent... Oopah, put the weapon down... Oopah?) AAaeee!~ */
  IF ~~ THEN DO ~CreateCreature("OOPAH2",[1282.3222],1)
EscapeAreaDestroy(90)
~ EXIT
  IF ~Global("X#VicGaz","GLOBAL",0)
InParty("viconia")
InMyArea("viconia")
!StateCheck("viconia",CD_STATE_NOTVALID)
~ THEN DO ~SetGlobal("X#VicGaz","GLOBAL",1)~ EXTERN ~VICONIJ~ 292
END

IF ~~ THEN BEGIN 3 // from:
  SAY #119010 /* ~Step right up!~ */
  IF ~~ THEN DO ~CreateCreature("OOPAH",[1282.3222],1)
~ EXIT
END

IF ~~ THEN BEGIN 4 // from:
  SAY #89489 /* ~Noooo!~ */
  IF ~~ THEN DO ~CreateCreature("OOPAH2",[1282.3222],1)
EscapeAreaDestroy(90)
~ EXIT
END

 

Maybe I am using it wrong, but from what I see currently it seems the function removes interjections completely.

Link to comment

Another finding in the usage of this function for BG1NPC:

It appears that I_C_T3 is turned into a I_C_T4 behavior. What I mean is that actions at the end of the dialogue state are put into the transactions to the interjecting NPC, not into the transactions *after* the NPC spoke the interjection. - If this is intended then it might be of interest that this lead to problems in this specific example:

After the group is arrested in BG city and put to prison, the help of Neb is needed to leave the prison. A cutscene is started which lets the group exit the prison:

Spoiler

IF ~~ THEN BEGIN 8 // from: 7.4
  SAY #76466 /* ~Let the solars come and I shall kill them too! In a world without justice, the gods are little more than a divine puppet show. Come, the tunnel's through the wall, here, and it is time we cut ourselves free from this confining womb.~ */
  IF ~~ THEN DO ~StartCutScene("Capcut02")
~ EXIT
END

BG1NPC adds interjections of several NPCs using I_C_T3 which give this if compiled conventionally. The transitions point to the NPCs' interjections, the start of the cutscene is moved after the interjections:

Spoiler

IF ~~ THEN BEGIN 8 // from: 7.4 20.4
  SAY #76466 /* ~Let the solars come and I shall kill them too! In a world without justice, the gods are little more than a divine puppet show. Come, the tunnel's through the wall, here, and it is time we cut ourselves free from this confining womb.~ */
  IF ~~ THEN DO ~StartCutScene("Capcut02")
~ EXIT
  IF ~Global("X#NEB8","GLOBAL",0)
InParty("jaheira")
InMyArea("jaheira")
!StateCheck("jaheira",CD_STATE_NOTVALID)
~ THEN DO ~SetGlobal("X#NEB8","GLOBAL",1)~ GOTO 27
  IF ~Global("X#NEB8","GLOBAL",0)
InParty("jaheira")
InMyArea("jaheira")
!StateCheck("jaheira",CD_STATE_NOTVALID)
~ THEN DO ~SetGlobal("X#NEB8","GLOBAL",1)~ EXTERN ~JAHEIRAJ~ 916
  IF ~Global("X#NEB8","GLOBAL",0)
InParty("dynaheir")
InMyArea("dynaheir")
!StateCheck("dynaheir",CD_STATE_NOTVALID)
~ THEN DO ~SetGlobal("X#NEB8","GLOBAL",1)~ GOTO 29
  IF ~Global("X#NEB8","GLOBAL",0)
InParty("dynaheir")
InMyArea("dynaheir")
!StateCheck("dynaheir",CD_STATE_NOTVALID)
~ THEN DO ~SetGlobal("X#NEB8","GLOBAL",1)~ EXTERN ~DYNAJ~ 215
  IF ~Global("X#NEB8","GLOBAL",0)
InParty("kivan")
InMyArea("kivan")
!StateCheck("kivan",CD_STATE_NOTVALID)
~ THEN DO ~SetGlobal("X#NEB8","GLOBAL",1)~ GOTO 33
  IF ~Global("X#NEB8","GLOBAL",0)
InParty("kivan")
InMyArea("kivan")
!StateCheck("kivan",CD_STATE_NOTVALID)
~ THEN DO ~SetGlobal("X#NEB8","GLOBAL",1)~ EXTERN ~KIVANJ~ 369
  IF ~Global("X#NEB8","GLOBAL",0)
InParty("ajantis")
InMyArea("ajantis")
!StateCheck("ajantis",CD_STATE_NOTVALID)
~ THEN DO ~SetGlobal("X#NEB8","GLOBAL",1)~ GOTO 39
  IF ~Global("X#NEB8","GLOBAL",0)
InParty("ajantis")
InMyArea("ajantis")
!StateCheck("ajantis",CD_STATE_NOTVALID)
~ THEN DO ~SetGlobal("X#NEB8","GLOBAL",1)~ EXTERN ~AJANTJ~ 256
END

Using the Smart I_C_T Function, the starting of the cutscene is moved into the transaction to the NPCs' interjections. This lead to the situation that the cutscene started while the dialogue box was still open, making the game hang:

Spoiler

IF ~~ THEN BEGIN 8 // from: 7.4 20.4
  SAY #76466 /* ~Let the solars come and I shall kill them too! In a world without justice, the gods are little more than a divine puppet show. Come, the tunnel's through the wall, here, and it is time we cut ourselves free from this confining womb.~ */
  IF ~~ THEN DO ~StartCutScene("Capcut02")
~ EXIT
  IF ~  Global("X#NEB8","GLOBAL",0)
InParty("jaheira")
InMyArea("jaheira")
!StateCheck("jaheira",CD_STATE_NOTVALID)
~ THEN DO ~SetGlobal("X#NEB8","GLOBAL",1)
StartCutScene("Capcut02")
~ EXTERN ~JAHEIRAJ~ 802
  IF ~  Global("X#NEB8","GLOBAL",0)
InParty("dynaheir")
InMyArea("dynaheir")
!StateCheck("dynaheir",CD_STATE_NOTVALID)
~ THEN DO ~SetGlobal("X#NEB8","GLOBAL",1)
StartCutScene("Capcut02")
~ EXTERN ~DYNAJ~ 155
  IF ~  Global("X#NEB8","GLOBAL",0)
InParty("kivan")
InMyArea("kivan")
!StateCheck("kivan",CD_STATE_NOTVALID)
~ THEN DO ~SetGlobal("X#NEB8","GLOBAL",1)
StartCutScene("Capcut02")
~ EXTERN ~KIVANJ~ 308
  IF ~  Global("X#NEB8","GLOBAL",0)
InParty("ajantis")
InMyArea("ajantis")
!StateCheck("ajantis",CD_STATE_NOTVALID)
~ THEN DO ~SetGlobal("X#NEB8","GLOBAL",1)
StartCutScene("Capcut02")
~ EXTERN ~AJANTJ~ 216
END

 

Link to comment

Join the conversation

You are posting as a guest. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

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.

×
×
  • Create New...