Roger Firth's IF pages | ![]() |
InfAct -- about Inform NPCs | ![]() |
![]() |
You probably know that the standard library verbs (in Grammar.h) include a number of grammars which include the creature token specifically targetted at NPCs.
Verb 'give' 'pay' 'offer' 'feed'
* held 'to' creature -> Give
* creature held -> Give reverse
* 'over' held 'to' creature -> Give;
Verb 'show' 'present' 'display'
* creature held -> Show reverse
* held 'to' creature -> Show;
Verb 'wake' 'awake' 'awaken'
* creature -> WakeOther
* creature 'up' -> WakeOther
* 'up' creature -> WakeOther;
Verb 'kiss' 'embrace' 'hug'
* creature -> Kiss;
Verb 'ask'
* creature 'about' topic -> Ask
* creature 'for' noun -> AskFor;
Verb 'tell'
* creature 'about' topic -> Tell;
Verb 'answer' 'say' 'shout' 'speak'
* topic 'to' creature -> Answer;
|
In this segment, we'll talk about the first group of actions -- Give, Show, WakeOther and Kiss -- which cover forms of interaction where you don't need to say anything. (A later segment will look at Ask, Tell and Answer.) These four actions, plus Attack and ThrowAt, are passed to an NPC's life property.
Object usher "gentleman usher" cloakroom
with name 'usher' 'gentleman' 'gentle' 'man',
description "The usher is smartly uniformed.",
life [;
Give:
if (noun ~= cloak) print_ret (The) self, " courteously refuses ",
(the) noun, ".";
move cloak to hook; give cloak ~worn;
"~I'll just hang it on here for you.~";
Show:
if (noun ~= cloak) print_ret (The) self, " smiles politely.";
"~I don't think I've ever seen one as dark as that!~";
WakeOther:
"~Sorry, I must have dozed off for a minute.~";
Kiss:
print_ret "On second thoughts, you don't know ", (ItOrThem) self,
" all that well.";
Attack:
print_ret (The) self,
" looks startled, but doesn't otherwise respond.";
ThrowAt:
print (The) self, " deftly catches ", (the) noun;
if (noun ~= cloak) " and returns it to you.";
move cloak to hook; give cloak ~worn;
" and carefully places it on the hook.^
~Things not been going too well today?~";
],
has animate male;
|
That's enough to handle some simple actions involving you and the NPC.
>SHOW THE CLOAK TO THE USHER "I don't think I've ever seen one as dark as that!" >THROW IT AT HIM (first taking the velvet cloak off) You take off the velvet cloak. The gentleman usher deftly catches the velvet cloak and carefully places it on the hook. "Things not been going too well today?" >KISS THE USHER On second thoughts, you don't know him all that well. |
Suppose you wish to add some extra forms of interaction. For example, you might fancy getting up close and personal with your NPC, specifically distinguishing between hug/embrace, touch/feel/pat, stroke/caress, fondle/grope, and kiss. Some appropriate verbs are already defined, but their behaviour isn't as well-tuned as you'd like. Also, whereas you can trap the Kiss action in your life property, the same isn't by default true for the Touch action. These lines are from Grammar.h.
Verb 'kiss' 'embrace' 'hug'
* creature -> Kiss;
Verb 'touch' 'fondle' 'feel' 'grope'
* noun -> Touch;
|
The matching action routines are in VerblibM.h (for clarity, I've change L__M() calls into plain print statements):
[ KissSub; if (ObjectIsUntouchable(noun)) return; if (RunLife(noun,##Kiss)~=0) rfalse; if (noun==player) "If you think that'll help."; "Keep your mind on the game."; ]; [ TouchSub; if (noun==player) "If you think that'll help."; if (ObjectIsUntouchable(noun)) return; if (noun has animate) "Keep your hands to yourself!"; "You feel nothing unexpected."; ]; |
To achieve the desired effect, we need to do three things:
First, here's a possible grammar:
Extend only 'embrace' 'hug' replace
* creature -> Hug;
Extend only 'touch' replace
* creature -> Pat
* noun -> Touch;
Verb 'pat'
* creature -> Pat;
Extend only 'feel' replace
* creature -> Stroke
* noun -> Touch;
Verb 'stroke' 'caress'
* creature -> Stroke;
Extend only 'fondle' 'grope' replace
* creature -> Fondle
* noun -> Touch;
|
Second, we need action routine which mimic the default behaviours of KissSub() and TouchSub():
[ HugSub;
if (ObjectIsUntouchable(noun)) return;
if (RunLife(noun,##Hug) ~= 0) rfalse;
if (noun == player) return L__M(##Touch,3,noun);
L__M(##Kiss,1,noun);
];
[ PatSub;
if (ObjectIsUntouchable(noun)) return;
if (RunLife(noun,##Pat) ~= 0) rfalse;
if (noun == player) return L__M(##Touch,3,noun);
L__M(##Touch,1,noun);
];
[ StrokeSub;
if (ObjectIsUntouchable(noun)) return;
if (RunLife(noun,##Stroke) ~= 0) rfalse;
if (noun == player) return L__M(##Touch,3,noun);
L__M(##Touch,1,noun);
];
[ FondleSub;
if (ObjectIsUntouchable(noun)) return;
if (RunLife(noun,##Fondle) ~= 0) rfalse;
if (noun == player) return L__M(##Touch,3,noun);
L__M(##Touch,1,noun);
];
|
Finally, the extended life property:
life [;
|
I'm sure your imagination is sufficient to tell you how this will perform at run-time.
(You could probably achieve much the same effect by using a before property instead of life. However, I'd recommend following in Graham's footsteps and use life for NPC interactions, unless you're sure you know what you're doing.)
Time to start getting vocal.