Jump to content

dialog action queueing


fuzzie

Recommended Posts

These are my current notes on how dialog actions are run in bg2. I would appreciate any comments/clarifications/etc; this is the result of several hours of in-game testing rather than any disassembly/etc work, but it matches my observations from GemRB of what the scripts expect the behaviour to be.

 

The basic idea is to repeat the following (vastly oversimplified):

 

 wait for a reply choice/whatever
evaluate the next set of conditions {
  show continue if we encounter a reply without text
  show a set of replies otherwise
}
add the reply actions to the current speaker's queue
if we're switching to a new speaker {
  wipe the new speaker's action queue
}

 

Normal "rules" for adding actions to the queue apply, for example:

 

* any running (blocking) actions are interrupted

* instants are only executed instantly if the queue is empty, otherwise they go on the queue

 

The queue of the current speaker is not processed during dialog even if the dialog has the non-pause bits set (so, this means actions don't start running on the current speaker, so don't get interrupted by the above).

 

Untested:

 

* Whether the queue is wiped or not when dialog is initiated, although it certainly looks like it: the above testing was done with an actor running a Dialog([PC]) in a script, which *seems* to wipe everything as soon as the dialog is started (but actions immediately after the Dialog one will still run, until something blocks).

* I didn't know how individual actor dialog pause settings change things.

* In the "if we're switching to a new speaker" bit above, I haven't checked what happens if we try moving to another dialog file (e.g. a banter file) on the current speaker instead.

* SetInterrupt(FALSE) does odd things: for instance, when it is set, the "queue wipe" above seems to wipe everything *except* any running (blocking) action.

* Loads of other things, probably.

 

Misc notes:

 

* You can happily refer to both the normal and banter dialogs on an actor, the engine doesn't seem to have any "normal dialog" and "interact dialog" mode.

* The target of Interact() is mostly irrelevant, except that it has to exist somewhere, and that the actors turn to face each other if within visual range.

Link to comment

I can confirm nearly everything you've worked out.

Replies are added via InsertResponse message, so they are wrapped with a SetInterrupt(FALSE/TRUE).

 

* Whether the queue is wiped or not when dialog is initiated, although it certainly looks like it: the above testing was done with an actor running a Dialog([PC]) in a script, which *seems* to wipe everything as soon as the dialog is started (but actions immediately after the Dialog one will still run, until something blocks).

Yep, the action list is cleared when the dialog starts.

 

* In the "if we're switching to a new speaker" bit above, I haven't checked what happens if we try moving to another dialog file (e.g. a banter file) on the current speaker instead.

Action list is not cleared. Like you said, only if the speaker changes.

 

 

Maybe I can add some info on how transitions are processed. This also involves the mysterious 0x20 transition flag. :)

The engine processes the transitions in three steps:

  1. First it looks at all transitions that have the 0x20 flag, and shows them if the trigger is true. (I think it'll also play the associated sound if there is one.)
  2. Next, it'll iterate again over all transitions, evaluate the trigger and if the transition does not have the HAS_TEXT (0x01) and EXIT_DIALOG (0x08) flags, it'll "show" (no text) the transition and set some info for continuing to the next state. And now it gets weird. After each such transition, it "removes" any previously displayed transition, that does not have the 0x20 flag.
  3. If there were any matching transitions in step two stop here. Otherwise, go through the transitions again and do "normal" processing, i.e. check trigger, display text (play sound) and/or set the continuation info. Last transition with trigger evaluating to true wins.
    If that process did not produce any valid replies, display "no valid replies".

I think it's mostly save to ignore the 0x20 flag. It looks a bit like telling the engine to "not touch that transition". It's also checked in a different place: After choosing a reply the engine removes the reply text (red color) and replaces it with the same text in a different color (light blue). If the flag is set the engine won't do the replace.

Link to comment

Fuzzie, I'm not sure how GemRB currently handles instant actions, but reading your post again, I think I need to clear something up: Instant actions are, like any other action, added to the list (queue). But when processing the list, the game has different "modes". (Not really, but I hope I can make this clearer in the next paragraph.)

 

If the game is unpaused and the creature is capable of doing actions (i.e. not dead, hold, etc.) it will fetch the next action from the list and do it. Afterwards it checks if the next action is an instant and also do it. (In the same AI round.) This repeats until the next action isn't an instant one or the list is empty.

The instants loop is also aborted, when the current action indicates that it wants to stay on the list. (i.e. return value is >= 0)

Even if the creature is dead, petrified, hold, etc. it will do that instant loop. There is something special for STATE_DEAD, I think it can discard a non-instant action after the loop is aborted.

When the creature is in dialogue, no actions are run except if the stat from opcode 0x0C2 is set.

But being in dialogue stops script processing, so I guess this is difficult to test. And remember, all of this only applies if the game is unpaused.

 

Now, when the game is paused, the creature will do one action per AI round, but only if it is instant. Again there is some special code to discard the current action. It's done when bit 31 of the creature flags is not set and there is something else in the list. (Bit 31 is non-interruptable, the engine modifies this internally.)

 

I hope this does not sound too confusing. :)

Link to comment

The part about scripts continue to run during pause is unexpected.

I thought the gametime is not progressing and this effectively disables any script execution.

 

I think, the break you see is to ensure the script loop is stopped right at the point where the Pause was issued.

Link to comment

User pause or dialogue pause? The above sounds correct for dialogue pause (assuming rounds are incremented by progress in the dialogue state)... I guess it could also make sense for user pause (the round isn't long enough to be totally perceptible, I guess, and queues don't typically grow that much).

 

I'll call 0x20 Priority response for now (they did use it a few times), but I'm not happy about it.

Link to comment
User pause or dialogue pause?

Doesn't matter, let's just say when gametime is paused.

And the AI update (round) I mentioned above is not to be confused with what most people refer to as script round. It calls the script processing routine, but only if the timers are right. (So it happens more often than the script round, and also when the game is paused.)

If someone is really interested in these obscure details, I guess I can paint a bigger picture.

 

I'll call 0x20 Priority response for now (they did use it a few times)

They did? Can you give some examples?

Link to comment
Doesn't matter, let's just say when gametime is paused.
Ah, OK. So it'll just pick off instants each time through.

 

They did? Can you give some examples?
Actually, I misremembered, so I can go back to Unknown and am happier for it. Sorry.
Link to comment

Archived

This topic is now archived and is closed to further replies.

×
×
  • Create New...