Actor states or similar in dialog

All in all I’m really impressed about dialog and quite a bit impressed by what can be accomplished with it so far! (The hot-reloading debugger had me at “ctrl-s”. It’s exactly in the way I like to create IF.)

Onward to my question. Maybe I’m a bad manual reader (most likely), but I haven’t figured out yet how to implement actor states in dialog in an efficient way. What would be the conventional dialog way of doing this. Would be very grateful for an example in that case. (I’m hoping for something similar to how it’s done in tads3 in order to break up complexity in regards to crafting NPC:s, so if there’s any other means to fulfill this purpose I’m open for that as well, just doesn’t know of it yet)

1 Like

Hi!

While TADS is object-oriented, Dialog is perhaps better described as aspect-oriented. You can still break up complexity, but you do it by keeping related rules together in the source code, rather than by putting code inside objects or classes.

NPCs are typically animated using (on every tick). But of course, putting all of your NPC antics inside the same rule would quickly become unreadable. So, keeping the aspects separate, you’d use one (on every tick) rule for every NPC, located close to the NPC definition in the source code.

Furthermore, the library exhausts (on every tick). Like this:

        (exhaust) *(on every tick)

This means that if you leave any choice points around, Dialog will come back and run them—essentially running every possible branch of the code after each move. In practice, you’d often want to limit this to a single action per NPC per tick. Thus:

%% This section contains everything related to Alice.

#alice
(name *)      Alice
(female *)
(proper *)
...

(on every tick)
        %% Here we do a normal query rather than a multi-query.
        %% This will ensure that Alice does, in fact, only do one thing per tick.
        (alice does one thing)

(alice does one thing)
        ~(alice has delivered the lollipop)
        (* is in room $AliceRoom)
        (current room $PlayerRoom)
        (if) ~($AliceRoom = $PlayerRoom) (then)
                (first step from $AliceRoom to $PlayerRoom is $Dir)
                (let * go $Dir)
        (else)
                (par)
                Alice hands you a blue lollipop.
                (now) (#lollipop is #heldby #player)
                (now) (alice has delivered the lollipop)
        (endif)

(alice does one thing)
        (player can see *)
        (par)
        Alice inspects a speck on the wall.

In the above example, Alice can be said to be in one of two states, depending on the value of the global flag (alice has delivered the lollipop). If the first (alice does one thing) rule succeeds, for instance because she hasn’t delivered the lollipop yet, then the second rule never executes. But if the first rule fails (for whatever reason—it could be because the lollipop has been delivered or because there is no path from Alice to the player), then the second rule executes which prints a message if Alice is within sight.

The term “actor state” is perhaps not the best way to describe what is going on here. It’s more apt to say that the story has a state (the global flag) that the actor is affected by. Now, in a game with lots and lots of actors with similar behaviour, it can make sense to model their state using per-object flags or per-object variables. But the quintessential Dialog way is to think of state as a property of the story, and thus to model it with a global flag or variable.

Some of this is also covered by the NPC chapter in the manual.

5 Likes

Thanks a lot! This clears things up for me. Especially the “on every tick” matter and that predicates can be named the same but splitted up. I’ll do some more reading now before asking again :wink:

I guess it’s kind of habitual of me, being so rooted in OO programming, to be so eager to want to put the actual state properties inside the objects instead of keeping them in global variables just for the sake of being structured. But I can see now how sentences as predicates make the meaning of it an easy read most of the time.

One thing I’m concerned about though from this example is having to think twice about the structure/ordering of the predicates in case several predicates evaluate to true (will need a lot of conditioning to keep them apart). But I’ll dig into this some more and see where I end up. Might be that my worries aren’t that neccessary :slight_smile: