Different approach to writing choice-based code

I am using Dialog to write a game which includes quite a bit of choice-based conversation. It’s rather painful, I find, to write the sort of boiler-plate needed, and you can easily get lost in it. One ends up writing so many nodes, it’s hard to see the structure.

Anyway, long story short, I’ve written (rapidly and dirtily) a little F# program which implements some of the basic structure of Inkle Studios’ (IMO brilliant) Ink language and will compile to Dialog code which can then be included in a game. (It’s only a subset because I assume that one will use Dialog to implement things like variables, conditional text, and so on. Besides, quick and dirty …

Sometimes a demonstration is simpler than an explanation. This source code:

=== TicketOffice

    An anxious and somewhat grubby official in a dirty
    cap stares at you.
    (par)
    "Where do you want to go?" she asks? -> ChooseDestination

=== ChooseDestination


    * "Basingstoke["]," you say. "I've always fancied
      going there.
      (par)
      "Can't think why," she says.
    * "Paris["]," you declare, "City of Lovers."
      (par)
      "Nice for some," she says. "My husband prefers
      Weston-Super-Mare. Anyway, it's no matter because
      this line don't go there." -> Choose_Destination
    * ["I just want some information"] 
      "Nowhere, actually," you say. "I was
      just wanting to ask when the next train to
      Hammersmith leaves." -> Information

    - She checks her computer. "I think we can manage
      that," she says. "What class?"
    
    * [First] "First class, of course," you say. "Do I
      look like the kind of person who travels second
      class?"
      (par)
      "You don't want to know," she says. She seems
      distinctly surly.
      (now)(#nameless is posh)
    * [Second] "Second class," you say. "Do I look like
      I'm made of money?"
      (par)
      "You took the words out of my mouth, dear," she says,
      "but we have to ask."

    - (par) She hands over the ticket.
      (par) "There you go love," she says. -> END

=== Information

    "Have you looked at the sign hanging over this window,"
    she says wearily. "T-I-C-K-E-T O-F-F-I-C-E. That's
    a ticket office, my love, not information centre. So
    what's it going to be?" -> ChooseDestination

Compiles to this Dialog code:

%% Automatically generated from testfile.conv
#TicketOffice
(display *)
    An anxious and somewhat grubby official in a dirty cap stares at
    you. (par) "Where do you want to go?" she asks?
(* flows to #ChooseDestination)

#ChooseDestination
(* offers #ChooseDestination_1)
(* offers #ChooseDestination_2)
(* offers #ChooseDestination_3)

#ChooseDestination_1
(display *)
    "Basingstoke," you say. "I've always fancied going there. (par)
    "Can't think why," she says.
(label *)
    "Basingstoke"
(* flows to #ChooseDestination_4)

#ChooseDestination_2
(display *)
    "Paris," you declare, "City of Lovers." (par) "Nice for some," she
    says. "My husband prefers Weston-Super-Mare. Anyway, it's no
    matter because this line don't go there."
(label *)
    "Paris"
(* flows to #ChooseDestination)

#ChooseDestination_3
(display *)
    "Nowhere, actually," you say. "I was just wanting to ask when the
    next train to Hammersmith leaves."
(label *)
    "I just want some information"
(* flows to #Information)

#ChooseDestination_4
(display *)
    She checks her computer. "I think we can manage that," she says.
    "What class?"
(* offers #ChooseDestination_4_1)
(* offers #ChooseDestination_4_2)

#ChooseDestination_4_1
(display *)
    "First class, of course," you say. "Do I look like the kind of
    person who travels second class?" (par) "You don't want to know,"
    she says. She seems distinctly surly. (now)(#nameless is posh)
(label *)
    First
(* flows to #ChooseDestination_4_3)

#ChooseDestination_4_2
(display *)
    "Second class," you say. "Do I look like I'm made of money?" (par)
    "You took the words out of my mouth, dear," she says, "but we have
    to ask."
(label *)
    Second
(* flows to #ChooseDestination_4_3)

#ChooseDestination_4_3
(display *)
    (par) She hands over the ticket. (par) "There you go love," she
    says.
(terminating *)

#Information
(display *)
    "Have you looked at the sign hanging over this window," she says
    wearily. "T-I-C-K-E-T O-F-F-I-C-E. That's a ticket office, my
    love, not information centre. So what's it going to be?"
(* flows to #ChooseDestination)

%% END OF GENERATED OUTPUT

I think that quite nicely demonstrates how (relatively) readable the Ink-lite code is compared to the code required to achieve that result in Dialog. Equally, however, the compiler produces Dialog code which is tolerably well-formatted and readable.

It’s hugely alpha in the sense that it’s not battle-tested, and I really still need to work a lot on things like decent parser errors, error-handling etc. Source code is here on Github (you will need dotnet tools to build it).

(Edited because since originally posting I’ve changed one aspect of syntax, and I don’t want non-functioning code sitting around.)

12 Likes