Let's Learn: Dialog

Let’s build some dialog-focused micro-games. I’ll post my source code for every prompt and encourage others to share theirs. Keep implementations minimal and focused on the prompt mechanics. If you want to go beyond the prompt, try to stick to mechanics found in Cloak of Darkness so beginners don’t get overwhelmed.

The first prompt

The Room Evolution Game
Prompt: Create a game where a room’s description evolves over time.
Goal: Use the (on every tick) or (on every tick in #room) predicate to create dynamic room descriptions.
Mechanic: Increment a global (current time $) variable every turn and write a (look #room) rule that varies over time.
Challenge: Describe the room in one state at Turn 1 and a significantly altered state by Turn 10 (e.g., from pristine to ruined, crowded to empty, warm to cold, etc.).

5 Likes

I’m slightly confused about what the challenge is here. You’ve said the effect you want to achieve (room description changes every turn), but you’ve also prescribed exactly how it should be implemented (increment a global variable and test it in (look $) so I’m not sure what you’re hoping people are going to contribute?

The prompt is the challenge if you want to play along. Sharing source examples and something creative is the value. You can ignore the rest if you want. I’m a complete newbie to dialog and my goal is to lean into a particular mechanic one at a time for learning, and see what creative things can be built with it.

Here’s the game I made today. A changing state from warmer to colder made me think of The Little Match Girl. I re-read it, saw it takes place on New Years Eve, and then had to do a take on it. Game attached. I’ll post the source code next year.

meaning-crisis.z8 (89 KB)

2 Likes

I am no expert but I would just start with the easiest option (where you get the state management for free).

The temperature is
(select)
	hot (or) hot (or) hot
(or)
	moderate
(or)
	cold
(or)
	very cold
(stopping)
.

That’s a good approach for when nothing else depends on the thing that’s changing, but it’ll have two problems in this situation:

  1. Time will only advance when you look. You can take a hundred turns doing something else, then look and it will only have advanced one step
  2. You can’t “see” the state of a (select) from anywhere else in the program. If you want descriptions of anything else to match the room description, you need to use a variable

In this case I only had to meet the criteria of the “prompt”.

The room is described when looking (the player looking doesn’t know there are exactly three times when the temperature is “hot” before it starts to change) and nothing else needs to change or know about it.

(select) is a useful construct and I did make use of it in addition to a counter.

Here’s the web playable version of what I came up with:

https://tzbits.com/dialog/meaning-crisis/

And here’s the source code:

https://tzbits.com/dialog/meaning-crisis/meaning-crisis.dg

I think dialog is reeealy nice to program in. Just about everything I’ve tried so far has behaved sensibly with no surprises. I did have problems with the text not rendering with [MORE] automatically for the intro so I threw in (any key) to keep it from scrolling off the page when the browser window is small. It is also nice that one can just start typing in a plain text editor and there’s no need for an IDE or anything like that.

2 Likes

doh, did I just walk into a room full of dialog experts and say, Hey folks, let’s learn dialog!?

I moved this over to a github project: GitHub - tzbits/learn-dialog

Being new to intfict.org feels a bit like Martin Rauch entering the supermarket in Deutschland 83.

1 Like

To be clear, it’s totally fine to post stuff like this here! Some of us are Dialog experts, but the majority of us aren’t. I might suggest (like Adam said) making it clearer that the “mechanic” line is how you’d recommend going about it, but you also want to see other approaches; but I’m all for things like this to get new people into Dialog.

3 Likes

Well.

This is almost it, except that you wouldn’t do this this way and also I didn’t really know how (or why) to do the look #room rule bit.

The output from this isn’t actually what I intend, as you have to enter >look twice in order to get to day two, and I don’t know why. So maybe that’s a learning opportunity for someone.

(story title)	All the Days of Christmas In This Room
(story author)	Jason Compton

(additional banner text) Based on the tzbits thingo

(story release 1)

(story ifid) 1-2-3-4-5-6-7-8-9-10-11-12

(intro)        This is the room where it happens. This is the room where all the presents pile up.
                (par)
                (banner)
                (try [look])

%% global vars

(global variable (days of christmas 1))

%% rooms

#trophyroom
(room *)
(name *) Christmas Trophy Room
(look *) This is where you take possession of all of your True Love's presents. You're extremely important, and worth it, so the partridge in the pear tree is just table stakes. (par)
  (days of christmas $A ) ($A > 1) Two turtle doves are here. You don't recall asking for so many birds. (par)
 (days of christmas $A ) ($A > 2) Three French hens are here. This is definitely a more bird-heavy Christmas than you'd expected. (par)
 (days of christmas $A ) ($A > 3) Four calling birds are here, and not welcome. (par)
 (days of christmas $A ) ($A > 4) Five golden rings sit in a nice display case. At least, it was nice, before the turtle doves fouled it. (par)
 (days of christmas $A ) ($A > 5) Six geese a-laying are here, and it smells like it. (par)
 (days of christmas $A)  ($A > 6) Given the volume of poultry, you're thinking that you and your True Love need to have a talk. Because now there are seven swans a-swimming in a very small kiddie pool. (par)
 (days of christmas $A ) ($A > 7) Eight maids a-milking have dropped by, ink fresh on their five-year milking contracts. So now you're gonna need to invest in dairy cattle. (par)
 (days of christmas $A ) ($A > 8) Nine ladies are dancing here, some kind of line dance broken up by the need to dodge the birds. (par)
 (days of christmas $A ) ($A > 9) Ten lords a-leaping are here. A couple of them are eyeing the ring case a little too eagerly. (par)
 (days of christmas $A ) ($A > 10) Eleven pipers are piping here. At least it's scaring some of the birds. (par)
 (days of christmas $A ) ($A > 11) Twelve drummers are drumming here. Between the honking, piping, and now the drumming, you've got a monster headache. (par)

%% other stuff

(on every tick in #trophyroom)
 (days of christmas $A)
 ($A plus 1 into $B)
 (now) (days of christmas $B)

(on every tick in #trophyroom)
 (days of christmas $A)
 ($A > 13) (par) This has all been lovely but it's just a bit too much. Boxing Day. Time to make some returns... (par)
 (game over { ...and have a serious chat with True Love. })

#player
(current player *)
(* is #in #trophyroom)
(descr *) You are the undisputed King of Christmas Present Getting.

This isn’t right because:

All the Days of Christmas In This Room
An interactive fiction by Jason Compton.
Based on the tzbits thingo
Release 1. Serial number DEBUG.
Dialog Interactive Debugger (dgdebug) version 0m/03. Library version 0.46.

Christmas Trophy Room
This is where you take possession of all of your True Love's presents. You're extremely important, and worth it, so
the partridge in the pear tree is just table stakes.

You are here.

> look
Christmas Trophy Room
This is where you take possession of all of your True Love's presents. You're extremely important, and worth it, so
the partridge in the pear tree is just table stakes.

You are here.

> look
Christmas Trophy Room
This is where you take possession of all of your True Love's presents. You're extremely important, and worth it, so
the partridge in the pear tree is just table stakes.

Two turtle doves are here. You don't recall asking for so many birds.

You are here.

> 

3 Likes

(on every tick) rules run after each time the player enters a command. But the first time the room description is printed by your code, it’s the result of the (try [look]) in the (intro), which doesn’t take a turn. So:

  • The intro prints the room description for day 1
  • The player gets to enter their first command (LOOK)
  • The game responds by printing the room description for day 1
  • The game ticks
  • The day number is increased to 2
  • The player gets to enter their second command (LOOK)
  • The game responds by printing the room description for day 2

You might also have noticed that “You are here” prints after the room description. This is because when Dialog encounters one of the conditions like ($A > 1) which is currently untrue, the (look #trophyroom) rule fails, so Dialog falls back to the default behaviour for (look $), which just prints the message “You are here”. Once you reach day 12, that message will disappear, because there’s no longer a failing condition in the rule.

2 Likes

Hmm, yes, I see.

The cheap fix is to append

                (days of christmas $A)
                ($A plus 1 into $B)
                (now) (days of christmas $B)

after the try [look]. Is there a more elegant one?

Aha, yes, I did notice that this was happening and wondered idly “that’s strange, I don’t remember Dialog being so obnoxious by default” but only got as far as verifying that it was a stdlib message without understanding why or noticing that it stopped when all conditions were satisfied.

I did notice some unexpected behavior if I had a failed rule higher up in the list (I tried to get fancy with the second static sentence once the birds added up) but didn’t wrestle with it. So, another reason not to do this this way!

Not really, if this is the behaviour you want (i.e. if you look on turn 1 you get the description for day 2; if you look on turn 2 you get the description for day 3, etc.).

Remember that you can use (or) to prevent the overall rule from failing if a condition within it fails. So you could do something like this:

(days of christmas $A )
{ ($A > 1) Two turtle doves are here. (par) (or) }
{ ($A > 2) Three French hens are here. (par) (or) }
{ ($A > 3) Four calling birds are here. (par) (or) }

Note that you don’t need to keep writing (days of christmas $A) every time, since $A is already bound - if it would have the same value each time, querying it does nothing, and if the value might have changed in the meantime then querying it again wouldn’t rebind $A, it would just fail.

Or a conditional, which is mostly equivalent:

(days of christmas $Days)
(if) ($Days > 1) (then) Two turtle doves are here. (par) (endif)
(if) ($Days > 2) (then) Three French hens are here. (par) (endif)
...

But the way I’d do the twelve days of Christmas would be a bit different:

(global variable (days of christmas 1))

(describe christmas $N)
    (days of christmas $Limit)
    { ($N > $Limit) (or) ~(number $Limit) } %% Stop recursion, we've gone far enough!
(describe christmas $N)
    (narrate present $N) (par)
    ($N plus 1 into $Np1)
    (describe christmas $Np1)

(narrate present 1) A partridge in a pear tree.
(narrate present 2) Two turtle doves.
...
(narrate present $N) Error: no present for day $N !

Recursion is often your friend in Dialog!

2 Likes

lol.

I was playing with something like this (since the song iterates backward on each round).

(global variable (days of christmas 1))

(narrate gift 1)
    (par) You're extremely important, and worth it, so in the pear tree is just table stakes.

(narrate gift 2)
    (par) Two turtle doves are here. You don't recall asking for so many birds.
    (narrate gift 1)

...

(narrate gift 12)
    (par) Twelve drummers are drumming here. Between the honking, piping, and now the drumming, you've got a monster headache.
    (narrate gift 11)

(narrate gift 13)
    (par) This has all been lovely but it's just a bit too much. Boxing Day. Time to make some returns...
    (game over { ...and have a serious chat with True Love. })

(look *)
    (par) This is where you take possession of all of your True Love's
    presents.
    (days of christmas $A)
    (narrate gift $A)
    ($A plus 1 into $B)
    (now) (days of christmas $B)

“Changing room descriptions” gave me an idea for something I wanted to try; apologies for taking some liberties with the original prompt. Here’s a short tribute to a classic piece of IF (I won’t name it, because it’s a spoiler if you haven’t played).

Sample transcript

Office

Your office contains a filing cabinet, a water cooler, a desk chair, and a desk. On the desk are a mobile phone, a paperback novel, and a satchel. Outside the window, you can see the snow.

A basketball lies on the floor.

> TAKE BASKETBALL

You take the basketball.

The paperback novel gives a soft sigh and falls apart into a pile of powdery white snow.

> OPEN FILING CABINET

You open the filing cabinet, revealing a manila folder.

The filing cabinet gives a soft sigh and falls apart into a pile of powdery white snow. The manila folder falls onto the floor.

> LOOK

Office

Your office contains a water cooler, a desk chair, and a desk. On the desk are a mobile phone and a satchel. Outside the window, you can see the snow. There are flecks of snow inside the office as well.

You see a manila folder here.

The desk chair gives a soft sigh and falls apart into a pile of powdery white snow.

> EXAMINE SATCHEL

It seems to be harmless.

A scientific calculator is in the satchel.

The mobile phone gives a soft sigh and falls apart into a pile of powdery white snow.

> TAKE FOLDER

You take the manila folder.

The water cooler gives a soft sigh and falls apart into a pile of powdery white snow.

> LOOK

Office

Your office contains a desk. On the desk is a satchel. Outside the window, you can see the snow. There are large piles of snow inside the office as well.

The basketball gives a soft sigh and falls apart into a pile of powdery white snow.

> INVENTORY

You have a manila folder.

The manila folder gives a soft sigh and falls apart into a pile of powdery white snow.

> LOOK

Office

Your office contains a desk. On the desk is a satchel. Outside the window, you can see the snow. There are great snowy hills inside the office as well.

The desk gives a soft sigh and falls apart into a pile of powdery white snow. The satchel falls onto the floor.

> TAKE SATCHEL

You take the satchel.

The satchel gives a soft sigh and falls apart into a pile of powdery white snow. The scientific calculator falls onto the floor.

> LOOK

Office

Your office is devoid of furniture. Outside the window, you can see the snow. There are vast mountains of snow inside the office as well.

The scientific calculator gives a soft sigh and falls apart into a pile of powdery white snow.

*** SNOW ***

Source code
(intro)
	(try [look])

(current player #player)
(#player is #in #office)

#office
(room *)
(name *) Office
(look *)
    (collect $F)
        *($F is #in #office)
        ~(item $F)
        ~($F = #player)
    (into $Furniture)
    (if) (nonempty $Furniture) (then)
        Your office contains (a $Furniture).
    (else)
        Your office is devoid of furniture.
    (endif)
    (collect $Obj)
        *($Obj is #on #desk)
    (into $DeskThings)
    (if) (nonempty $DeskThings) (then)
        On the desk (is $DeskThings) (a $DeskThings).
    (endif)
    Outside the window, you can see the snow.
    (snow level is $S)
    {
        ($S > 0)
        There are
        (if) ($S < 3) (then) flecks of snow
        (elseif) ($S < 5) (then) drifts of snow
        (elseif) ($S < 7) (then) large piles of snow
        (elseif) ($S < 9) (then) great snowy hills
        (else) vast mountains of snow (endif)
        inside the office as well.
        (or)
    }
#cabinet
(name *) filing cabinet
(openable *)
(container *)
(* is #in #office)
(snowable *)

#folder
(name *) manila folder
(item *)
(* is #in #cabinet)
(snowable *)

#phone
(name *) mobile phone
(item *)
(* is #on #desk)
(snowable *)

#book
(name *) paperback novel
(dict *) book
(item *)
(* is #on #desk)
(snowable *)

#satchel
(name *) satchel
(item *)
(container *)
(* is #on #desk)
(snowable *)

#calculator
(name *) scientific calculator
(item *)
(* is #in #satchel)
(snowable *)

#cooler
(name *) water cooler
(* is #in #office)
(snowable *)

#ball
(name *) basketball
(dict *) basket ball
(item *)
(* is #in #office)
(appearance *) A basketball lies on the floor.
(snowable *)

#chair
(name *) desk chair
(heads *) chair
(* is #in #office)
(snowable *)

#desk
(name *) desk
(heads *) desk
(supporter *)
(* is #in #office)
(snowable *)

%% Give all the portable items their default appearance
($Obj is handled)
    (item $Obj)

(can crumble $Obj)
    (snowable $Obj)
    ~($Obj is nowhere)
    %% Don't crumble things inside closed containers
    (if) ($Obj is #in $Parent) ~(room $Parent) (then)
        (open $Parent)
    (endif)

(choose crumbling item $Obj)
    (collect $Candidate)
        *($Candidate is in scope)
        (can crumble $Candidate)
    (into $List)
    (length of $List into $NMax)
    (random from 1 to $NMax into $N)
    (nth $List $N $Obj)

(on every tick)
    (choose crumbling item $Obj)
    (par) (The $Obj) gives a soft sigh and falls apart into a pile of powdery white snow.
    (collect $Child)
        *($Child has parent $Obj)
    (into $Children)
    (if) (nonempty $Children) (then)
        ($Obj has parent $Parent)
        (if) ($Parent = #player) (then)
            ($NewParent = #office)
        (else)
            ($NewParent = $Parent)
        (endif)
        ($Obj has relation $Rel)
        (The $Children) fall(s $Children) onto
        (if) (current room $NewParent) (then)
            the floor
        (else)
            (the $NewParent)
        (endif).
        (exhaust)
        {
            *($Child is one of $Children)
            (now) ($Child is $Rel $NewParent)
        }
    (endif)
    (now) ($Obj is nowhere)
    (if) (snow level is 10) (then)
        (game over { SNOW })
    (endif)

(snow level is $N)
    (accumulate 1)
        *(snowable $Obj)
        ($Obj is nowhere)
    (into $N)

Actually, the biggest time sink here was getting the contents of the room to display properly without the player having to examine everything. I’m loving working with Dialog, but I do generally prefer the Inform default of telling the player about everything in sight to Dialog’s assumption that you’ll write carefully-crafted (appearance $) predicates for everything, especially when dealing with a bunch of supporters and containers. (I might start a further thread on this at some point, since I’m interested to know how others are handling it, but I don’t want to derail this one.)

4 Likes