Roger Firth's IF pages

Home

InfAct -- about Inform NPCs

Email
Back up

It's probably occurred to you by now that this conversation stuff is tricky. The occasional two-line interchange under controlled circumstances isn't too bad, but if you're contemplating anything approaching free-flowing give'n'take, you're in for a hard slog. Here are some library packages which may slightly ease the burden.

PhTalkOO.h

The PhTalkOO.h package gives you the simple menu-based conversational system which was at the heart of Adam Cadre's award-winning Photopia. It's quite easy to use; your NPC must inherit from the Character class and three new properties are needed, with most of the effort going into Respond:

 
Object  usher "gentleman usher" cloakroom
  class Character
  with  name 'usher' 'gentleman' 'gentle' 'man',
        description "The usher is smartly uniformed.",
        InitQuips [; self.QuipsOn(3, 0,1,2); ],
        SayQ [ q; switch (q) {
            0:  "Hello.";
            1:  "Nice uniform, mate. Just out the navy, are you?";
            2:  "Blimey, only one hook?";

            3:  "Please hang up my cloak.";
            4:  "Thanks very much.";

            5:  "What's tonight's opera?";
            6:  "Ah, Verdi.";

            7:  "Not many people around?";
            8:  "True enough - it's a nasty night to be out.";
            } ],
        Respond [ q; switch (q) {
            0:  self.QuipsOff(3, 0,1,2); self.QuipsOn(3, 3,5,7);
                "~Good evening.~";
            1:  self.QuipsOff(3, 0,1,2); self.QuipsOn(3, 3,5,7);
                "The usher smiles politely but doesn't reply.";
            2:  self.QuipsOff(3, 0,1,2); self.QuipsOn(3, 3,5,7);
                "~I'm afraid the others have been mislaid.~";

            3:  self.QuipOff(q); self.QuipOn(q+1);
                move cloak to hook; give cloak ~worn;
                "~Certainly.~";
            4:  self.QuipOff(q);
                "~Think nothing of it - it's what I'm here for.~";

            5:  self.QuipOff(q); self.QuipOn(q+1);
                "~It's Don Giovanni.~";
            6:  self.QuipOff(q);
                "~We're doing Figaro tomorrow - another, ahem, Mozart gem.~";

            7:  self.QuipOff(q); self.QuipOn(q+1);
                "~Indeed not - it must be the weather.~";
            8:  self.QuipOff(q);
                "~I can see that from your cloak.~";
            } ],
  has   animate male;

That's virtually all you need do, apart from invoking InitQuips from your Initialize() routine. Here's what it looks like:

 
>TALK TO THE USHER
What would you like to say?

[1] Hello.
[2] Nice uniform, mate. Just out the navy, are you?
[3] Blimey, only one hook?

Select an option or 0 to say nothing >> 3

"I'm afraid the others have been mislaid."

>AGAIN
What would you like to say?

[1] Please hang up my cloak.
[2] What's tonight's opera?
[3] Not many people around?

Select an option or 0 to say nothing >> 2

"It's Don Giovanni."

>AGAIN
What would you like to say?

[1] Please hang up my cloak.
[2] Ah, Verdi.
[3] Not many people around?

Select an option or 0 to say nothing >> 2

"We're doing Figaro tomorrow - another, ahem, Mozart gem."

>AGAIN
What would you like to say?

[1] Please hang up my cloak.
[2] Not many people around?

Select an option or 0 to say nothing >> 1

"Certainly."

>AGAIN
What would you like to say?

[1] Thanks very much.
[2] Not many people around?

Select an option or 0 to say nothing >> 1

"Think nothing of it - it's what I'm here for."

>AGAIN
What would you like to say?

[1] Not many people around?

Select an option or 0 to say nothing >> 1

"Indeed not - it must be the weather."

>AGAIN
What would you like to say?

[1] True enough - it's a nasty night to be out.

Select an option or 0 to say nothing >> 1

"I can see that from your cloak."

>AGAIN
You can't think of anything in particular to say.

Converse.h

Converse.h is another menu-based system, but in this case the menus are more formal (and, I think, more intrusive). There'a quite a bit to set up, at the head and foot of the game (including three other packages to be included first):

 
Constant Story      "Cloak of Darkness";
Constant Headline   "^A basic IF demonstration.^";
Constant MANUAL_PRONOUNS;
Constant MAX_SCORE  2;

Replace  DoMenu;
Replace  LowKey_Menu;

Include "Parser";
Include "VerbLib";

Constant ALTMENU_PROP_STUBS;
Constant CONVERSE_NO_GRAMMAR;
Constant CONVERSE__TX = "Talk about...";
Include "Utility";
Include "DoMenu";
Include "AltMenu";
Include "Converse";
dots
Verb 'talk' 'converse' 'interview'
        * creature                  -> Converse
        * 'with'/'to' creature      -> Converse;

and for the NPC himself:

 
Object  usher "gentleman usher" cloakroom
  class Conversor
  with  name 'usher' 'gentleman' 'gentle' 'man',
        description "The usher is smartly uniformed.",
        conversation cc_usher,
  has   animate male;

Conversation_controller cc_usher;

Topic   -> t0 "Greet the usher"
  with  playerpart "Hello.",
        convpart [;
            usher.remconv(t0); usher.remconv(t1); usher.remconv(t2);
            usher.putconv(t3); usher.putconv(t5); usher.putconv(t7);
            "~Good evening.~"; ];
Topic   -> t1 "The usher's uniform"
  with  playerpart "Nice uniform, mate. Just out the navy, are you?",
        convpart [;
            usher.remconv(t0); usher.remconv(t1); usher.remconv(t2);
            usher.putconv(t3); usher.putconv(t5); usher.putconv(t7);
            "The usher smiles politely but doesn't reply."; ];
Topic   -> t2 "The hook on the wall"
  with  playerpart "Blimey, only one hook?",
        convpart [;
            usher.remconv(t0); usher.remconv(t1); usher.remconv(t2);
            usher.putconv(t3); usher.putconv(t5); usher.putconv(t7);
            "~I'm afraid the others have been mislaid.~"; ];

Topic   t3 "Your cloak"
  with  playerpart "Please hang up my cloak.",
        convpart [; usher.remconv(self); usher.putconv(t4);
            move cloak to hook; give cloak ~worn;
            "~Certainly.~"; ];
Topic   t4 "His reply"
  with  playerpart "Thanks very much.",
        convpart [; usher.remconv(self);
            "~Think nothing of it - it's what I'm here for.~"; ];

Topic   t5 "The opera"
  with  playerpart "What's tonight's opera?",
        convpart [; usher.remconv(self); usher.putconv(t6);
            "~It's Don Giovanni.~"; ];
Topic   t6 "His reply"
  with  playerpart "Ah, Verdi.",
        convpart [; usher.remconv(self);
            "~We're doing Figaro tomorrow - another, ahem, Mozart gem.~"; ];

Topic   t7 "The lack of people"
  with  playerpart "Not many people around?",
        convpart [; usher.remconv(self); usher.putconv(t8);
            "~Indeed not - it must be the weather.~"; ];
Topic   t8 "His reply"
  with  playerpart "True enough - it's a nasty night to be out.",
        convpart [; usher.remconv(self);
            "~I can see that from your cloak.~"; ];

At run-time, the TALK verb switches from normal display to a full screen menu; you remain within the menu interface until you end the conversation, whereupon the normal screen returns (with no evidence of what has taken place). This doesn't show up well on a normal transcript, so I'll give a couple of screen shots:

 
You can see a gentleman usher here.

>TALK TO THE USHER



 
You can see a gentleman usher here.

>

On to giving orders.