Dialog

In case you ever make any progress with your emacs-mode for dialog, let me know. It’s been very helpful so far!

1 Like

Yay! Congrats for the Best Technological Development!

4 Likes

Huge congrats! Incredibly cool.

5 Likes

I have created a mostly-complete conversion of Pick Up the Phone Booth and Die to Dialog.

…enjoy?

Improvements welcome.

4 Likes

Incidentally, is there an official/accepted way to disassemble a Dialog Z-Machine binary? putpbad.z5 seems to break txd’s tiny brain, generating a bunch of errors and >100 MB of output. (OSX build of txd from ztools731)

Txd works, but you have to use -g to stop it from trying to analyze the grammar table. That’s because in Dialog, grammar is just ordinary code.
Dialog Z-code is highly optimized and tricky to follow. Text strings are useful landmarks. Check out zcode.h to learn what the global variables do. You can also run dialogc in quadruple-verbose mode (-vvvv) to see the intermediate code, which is fairly close to the final Z-code, but better annotated. The routines end up in a different order, though.
Happy hacking!

2 Likes

‘but this one has the words “PHONE BOOTH” scratched out and “P#0N3 B00TH” instead.’ …

I didn’t notice until watching my own video playback that Dialog was understandably confused about the # in p#on3.

Escaping it in the (descr) as

P\#0N3

works fine.
But in the dict, it didn’t help:

(dict *)	p\#0n3 b00th

b00th is fine, but I still can’t get the game to treat p#on3 as a valid way to refer to the booth.

Is there a solution, other than “don’t do this”? :slight_smile:

(The video is at https://www.youtube.com/watch?v=ciEBW61IUPo , for the curious.)

Hi!

This sounds like a bug, but I’m not able to reproduce it. Here, “p\#0n3” works correctly on all compiler backends. In your message, you’ve spelt it with a zero in one place, and the letter o in another. Could that be the root cause, or is it just a typo in the message?

I enjoyed watching the video! It allowed me to see the language through a beginner’s eyes, which was cool and also provided useful feedback.

It seems I have to clarify the role of (notice $) in the manual. Notice has nothing to do with the appearance of an object, and defining a rule for (appearance $ $ $) is sufficient to make the object stand out in the room description. Notice binds a pronoun to the object. In this case, because the phone booth is neither (male $), (female $), nor (plural $), the pronoun “it” is bound to it. Hence, the player can type “pick it up” and die.

Instead of the (victory lap $) thing, I would use select/stopping, like this:

(on every tick in #townsquare)
	(booth has been pushed)
	(select)
	(or)
		(par)
		A familiar sound ...
		(game over {You have won})
	(stopping)

On line 207, visible at 14:15, it looks like you have a bug: The condition ($Max) invokes the predicate ($), which is used for hyperlinks. The original code from the library queries (current score $Max), which is something else. You can probably remove this condition altogether, since you already know that a maximum score is defined.

Thanks for taking an interest in Dialog, and for making a nice video!

(I am embarrassed to report that it was in fact me not correctly entering “p#0n3” in-game. Moving right along…)

Thank you for the illustration of how select/or/stopping can be used for this kind of simple counter! Much cleaner.

I’ve cleared out the bad/unnecessary $Max code, and will work on comprehending better what you said about why exactly that condition was not just unnecessary (because, as you say, I as the author know there’s a maximum score) but why I was also using $Max incorrectly.

Thanks for the correction on (notice $), I wish I could explain better why I felt it was necessary.

Speaking of properly defining the #booth:

What would be the Dialog way to replicate this behavior from the Inform original?

[game starts, first move entered is]
>take
(the phone booth)
You grunt with all your might and heave [etc]
    *** You have died ***

My Dialog version produces

> take
(I only understood you as far as wanting to take something.)

Looking at trace info in the debugger produces a lot of things I don’t understand! #booth is mentioned as being in scope and visible but obviously isn’t being chosen.

I don’t know what the Inform code was doing. In ZILF, the TAKEBIT flag is enough to make that maneuver work.

Is it just a design characteristic of the Dialog (and/or the stdlib) that a simple TAKE isn’t expected to work? Or is there a simple way of enabling this behavior that I’ve missed?

1 Like

strange, because of the

(notice #booth)

whose AFAICT should have put the booth in scope and visible to the disambiguation.

Best regards from Italy,
dott. Piergiorgio.

Scope is determined based on where objects are located. The phone booth is in the same room as the player and visible, and therefore in scope. It’s also possible to put extra objects in scope:

(add #foo to scope)
	...typically with some condition here...

The predicate (notice $) is unrelated to scope, and unrelated to appearances. It only binds the pronoun ‘it’ (or ‘him’, ‘her’, or ‘them’ as appropriate) to the object.

However, there’s one more thing to know: The Dialog standard library (unlike Inform) automatically unbinds pronouns when the corresponding objects go out of scope. So if you examine statue, then go north, then try to take it, the game will respond that it only understood you as far as wanting to take something, because ‘it’ is no longer meaningful, since the statue is no longer in scope. (Unless this was a living statue that followed you to the adjacent room. In that case, ‘it’ still refers to it.)

2 Likes

This behaviour is not built-in by default, but you can add a rule for it:

(understand [take] as [take $Obj])
	*($Obj is in scope)
	(item $Obj)
	~($Obj is hidden)

This will backtrack over every object in scope, and then ensure that only items (takable objects) are returned. The last line is only necessary if there are hidden objects in the game at all.

2 Likes

For a joke game reimplementation I’m more inclined to just stick with the library defaults and celebrate differences than to make rule changes, but that’s a helpful example for cases where it might actually be desirable, thank you.

Hello! I just discovered Dialog and I am enamored with its power and readability; thank you so much for all your work on this!

I have a question, and it is kind of an odd one. Is there a way to do Unicode input / output? It seems from Googling that (certain versions of?) the Z-machine standard allow a limited number of Unicode characters from the BMP plane. The simple use case is inputting and outputting character variants like å, ñ, etc. More ambitiously, I believe Dialog might be capable of parsing Japanese kana input (which is difficult because the language does not put spaces between words, “take the dog” -> 「いぬをとる」), although I’m also not sure if there is a way to do splitting of a dictionary ‘word’ into multiple smaller words (split いぬをとる into いぬ and とる). Maybe it’s not possible, I’m not sure.

Hi, and thanks!

That is an intriguing idea. I think it boils down to two new requirements. One, which I’ve been meaning to implement anyway, is to improve unicode support in the Z-machine backend. Like you say, the Z-machine standard supports using a custom character set based on arbitrary BMP characters, but the Dialog compiler doesn’t make use of this feature yet.

The second requirement, as you point out, is the ability to split a dictionary word into single-character words, and then join them back together. This is currently not possible in the language, but it could be added.

I’ve dabbled in Japanese grammar myself; it’s a fascinating subject. If I were to attempt to parse Japanese input in Dialog, I would start by converting it into a list of characters, as discussed above. Then, as a first approximation, I would probably try something like *(split $Input by [は を も に へ で が] into $Prefix and $Verb) to split off the verb at a valid particle. For each possible split, I would join the characters of $Verb back into a single dictionary word, and match that against the grammar rules.

Hmm. Now that I think about it, it makes more sense to break down the input into chunks of characters that each end with a particle. To do this efficiently, I think a good trick would be to first reverse the list, so the particle ends up as the head element of each chunk. Then one could write a recursive rule definition that backtracks over every possible parse.

So many possibilities, and so little time. I’ll have to leave this puzzle for somebody else to solve. But the two feature requests are duly noted.

Never thought of parsing a Japanese sentence in reverse, but that does seem like it might be a fruitful approach.

Dialog version 0h/01 (library 0.30) is out.

  • This version introduces support for embedded graphics, as well as links to feelies and external web sites, when compiling for the Å-machine. Read all about Resources in the manual.

    • Graphics and feelies are stored inside the .aastory file, and this part of the file format has been carefully designed to be accessible and malleable. This means that a build process could involve converting a large story file intended for the web into a small story file for 8-bit systems, and vice versa. It also means that external links can be kept up to date even if the source code to a game is lost.
  • A new built-in predicate called (interpreter supports quit) reports whether (quit) is handled in a way that is meaningful to the player. The predicate fails under the Å-machine web interpreter, for instance, because there’s no way for the interpreter to close the browser tab. The game-over menu in the standard library has been redesigned slightly, and no longer suggests QUIT when that action makes no sense.

2 Likes

Hello!

I am having trouble getting Dialog to understand that “pushing a button (switch)” means “switching the button (switch)”. What is the right way to do this?

(library links enabled)
(default actions enabled)

%%%%

(intro)
	(enter #your-room)

%%%%

#player

(current player *)

%%%%

#your-room

(name *)
	Your Room
(look *)
	It's your room.
(room *)
(singleton *)

%%%%

#the-button

(name *)
	button
(* is #in #your-room)
(descr *)
	(if) (switched on *) (then)
		It is switched on.
	(else)
		It is switched off.
	(endif)
(switchable *)
(understand [push | $Words] as [switch | $Words])

Thank you!

Hi!

Excellent question! I have a short answer and a long answer. The short answer is:

#the-button

(name *)
	button
(* is #in #your-room)
(descr *)
	(if) (* is on) (then)
		It is switched on.
	(else)
		It is switched off.
	(endif)
(switchable *)
(instead of [push *])
	(if) (* is on) (then)
		(try [switch off *])
	(else)
		(try [switch on *])
	(endif)

Note (* is on) instead of (switched on *).

The long answer is related to (understand $ as $). This predicate takes raw input, in the form of a list of dictionary words, and converts it into an action. Actions are lists of keywords (which are dictionary words) and objects. So the input parameter might be [pick the red ball up] and the output parameter might be [take #redball].

By defining a rule as (understand [push | $Words] as [switch | $Words]), you are just moving the raw words of input over to the right-hand side. The action becomes something like [switch the button], whereas we probably want something like [switch #the-button]. To achieve that, we delegate to the library predicate (understand $Words as non-all object $Obj), or one of its variants. Thus:

(understand [push | $Words] as [switch $Obj])
	*(understand $Words as non-all object $Obj)

But there is another complication: The standard library doesn’t have a generic [switch $] action. It has two: [switch on $] and [switch off $]. But on the other hand, it has a generic [push $] action for verbs like push, press, move, and shove. So we could either latch onto that, as I did in the short answer above. Or we could add a couple of new parsing rules:

(understand [push | $Words] as [switch on $Obj])
	*(understand $Words as non-all object $Obj)
	($Obj is off)

(understand [push | $Words] as [switch off $Obj])
	*(understand $Words as non-all object $Obj)
	($Obj is on)

Or, according to taste:

(understand [push | $Words] as [switch $How $Obj])
	*(understand $Words as non-all object $Obj)
	(if) ($Obj is on) (then)
		($How = @off)
	(else)
		($How = @on)
	(endif)

There’s a subtle difference between adding parsing rules (as in the latter two examples) and adding an action-handling rule (“instead of”). If parsing rules are added, this can lead to ambiguities. So, “push button” could result in “Did you want to 1. push the button, or 2. switch the button on?”. To prevent this question, just add:

(unlikely [push #the-button])

With an instead-of-rule, there’s only one way to parse the input, namely as [push #the-button]. Then, when the action is attempted, it gets redirected to one of the switch-actions instead.

Finally, I’ll add that this particular redirection seems like it should be part of the standard library, and I might add it in a later version. Specifically, I might add a [switch $] action that responds to switch, toggle, and push if the object is switchable, and that redirects to switch-on or switch-off depending on the current state of the object.

3 Likes

Why are numbers in Dialog so limited? It looks like they’re being stored as 14 bits (unsigned 0-16383), and I can’t think of an architecture where that makes sense. (I’m still reading the documentation, so maybe the standard library helps with this, but it’s still weird.)

Also, is there an Å-code interpreter for the Commodore 64, or should I stick to Z-code if targeting that architecture? I ask because you specifically mention Å-code being designed for low-end machines.

1 Like