The trouble is, if only two pennies are in hand, the parser's output is
seriously misleading:
>give pennies to bob
You can't use multiple objects with that verb.
This is normally correct -- but not in this particular situation,
because you CAN give pennies to Bob. The error message will quite likely
dissuade the player from trying an action that WILL work when the three
pennies are all in hand.
How can I avoid misleading the player?
Can I override the error message -- but ONLY when the word the player
types is "pennies"? That would be ideal. What I'd like would be this:
>give pennies to bob
You don't seem to be holding all three pennies.
That might be a minor spoiler (if the player has only found two of the
pennies), but at least it's not misleading. How would I trick Inform
into doing that?
Thanks!
--JA
My first instinct would be to attempt a "Does the player mean ..."
rule (or a short stack of them, enough to get the priorities clear).
My second instinct would be to give the underlying objects root names
which don't include "penny" or "pennies" and then write an ugly stack
of hackish "understand as" rules and tweak them and bash away at them
and pull my hair out til something good happens.
My third instinct would be to collapse in despair and begin playing
with my toes. Eventually, I'd name them. Eventually, it would occur to
me that they're a kind of "toe collective" when manipulated as a
group, and then I'd start sobbing.
It's very possible that none of the three approaches would help very
much. Just keeping you company 'til someone knowledgeable shows up :)
I'm wrong or the plural of penny is "pence" ?
Mr. Nelson, being British, perhaps has implemented this irregular case
of plural in the parser; I can suggest to try with "pence" instead of
"penny" ?
Best regards from Italy,
Dott. Piergiorgio.
That's the British plural, yes. It's not used in the U.S.
> Mr. Nelson, being British, perhaps has implemented this irregular case
> of plural in the parser; I can suggest to try with "pence" instead of
> "penny" ?
It's not about pence, really. The problem is that I need to intercept
and rewrite the parser's error message output in one very specific
situation, namely: (a) the action is 'give' or 'show', (b) the player
types 'pennies' (or 'coins' or some other understood plural form) as the
noun, and (c) one or two of the indistinguishable penny objects (plural
"pennies") are in the player's hand, but not three of them, because if
three are in the player's hand my "penny collective" object will insert
itself into the scene and handle the command.
Actually, though, the message would be just as misleading if the player
typed 'give penny and rabid gerbil to bob'. Even then, I don't want the
parser misleading the player into thinking that it's not possible to
give multiple objects with a single command. Except that in any other
case, of course, there's no way that the parser should be expected to
process the action, so it has to put forth an error message explaining
the problem.
I'd settle for "Generally speaking, you can't use multiple objects with
that verb" as the _default_ error message, but I'll still need a
specific error message in response to 'give pennies to bob'.
--JA
> I'd settle for "Generally speaking, you can't use multiple objects with
> that verb" as the _default_ error message, but I'll still need a
> specific error message in response to 'give pennies to bob'.
>
> --JA
I would come at this from the other direction: make giving and showing
multiple objects into valid actions, then write check rules to
restrict those cases where the multiple object list so generated
includes non-pennies or an insufficient number of pennies. That way,
the parser *will* have matched the objects and you'll have a lot more
information to work with in generating the error message.
To do this, you'll probably need to borrow some stuff about digging
into the multiple object list from the recipe book section "Commands >
Actions on Multiple Objects".
S. John Ross wrote:
>
> My first instinct would be to attempt a "Does the player mean ..."
> rule (or a short stack of them, enough to get the priorities clear).
I'm not sure how I'd approach it that way. What the player means is clear.
> My second instinct would be to give the underlying objects root names
> which don't include "penny" or "pennies" and then write an ugly stack
> of hackish "understand as" rules and tweak them and bash away at them
> and pull my hair out til something good happens.
One way to do that would be to make the three penny objects secretly
distinguishable from one another. Make one a fgdxkz penny, one a mybbbbd
penny, and so on. But if I do that, then when my collective-penny object
isn't in scope the parser will respond to 'give pennies to bob' with
"You can't see any such thing," even though the player is holding two of
what she _thinks_ are pennies. Plus, the inventory will now list "a
penny, a penny, and a penny". That hardly seems an improvement.
I could turn them into a penny, a nickel, and a dime ... but for reasons
having to do with the game scenario, that's not a very good idea. Plus,
it would force the player to 'give dime to bob', 'give nickel to bob',
and 'give penny to bob' separately, which would be fairly annoying; you
couldn't 'drop the coins', and so on.
> My third instinct would be to collapse in despair and begin playing
> with my toes. Eventually, I'd name them. Eventually, it would occur to
> me that they're a kind of "toe collective" when manipulated as a
> group, and then I'd start sobbing.
Toe-playing -- good idea. My third instinct is to go back to TADS, but I
refuse to be defeated by this! In principle, any reasonably mature IF
language can model any story situation by accepting any input and
producing any output. So I decline to believe Inform can't do it.
Using a penny collective object was a workaround in the first place. I
implemented it specifically to allow the player to buy something using
the command 'give pennies to bob'. It works fine ... as long as the
player is holding all three pennies. But if there are only two pennies
nearby, the penny collective is not in scope, so the parser's error
message is wrong-wrong-wrong, and I didn't realize that until now.
In TADS, I could quite easily get in and mess with the code for the
penny collective object. I could have it be in scope whenever ONE or
more pennies is in scope, but pretend not to be. I could do the same
thing in I6 using parse_name (and have done so, in fact).
But given the rules-based design of I7, I'm lost. I don't know which
rules are operating, or in what order, much less how to get in and
tinker with the order of execution. And oddly enough, the 'rules all'
utility command doesn't help. If I grab exactly two pennies, go into the
room where the intended recipient is waiting, and type 'rules all'
followed by 'give pennies to bob', the rule that prevents giving
multiple objects in one command IS NOT LISTED in the output. Nor, for
that matter, is the rule that produces the default error message. I get
a list of about 30 "[Rule 'After deciding the scope of the player'
applies.]", followed by some rules that don't apply, and then the output.
I really don't want to turn this into yet another
kvetching-about-Inform-7 thread, but maybe I will. I can't help feeling
that the manual should explain the mechanics of the give/show code, and
show how to alter it when needed. 7.4 in the Recipe Book doesn't seem to
address my problem at all. The manual does (in Ex. 369) direct me to the
Extensions page on the web, and from gazing at the documentation for
Custom Library Messages it appears I might be able to hack one message
in one situation ... if I knew which message I was trying to hack! But I
don't, and 'rules all' doesn't tell me.
Nor do I want to hack one particular message in one particular place,
really. What I want, in fact, is to be able to use the give/show action
to process three indistinguishable objects with a single command -- but
only in this one particular situation. Then I'll use Custom Library
messages to hack the default message in ALL cases, and I'll be good to go.
Come to think of it, though -- if a group of objects is
indistinguishable, shouldn't the library ALWAYS allow you to use the
plural to refer to and manipulate all of the objects at once, including
when the action is 'give' or 'show'?
> It's very possible that none of the three approaches would help very
> much. Just keeping you company 'til someone knowledgeable shows up :)
It's appreciated.
--JA
Yes, I can see how that might, in the end, get me where I want to go. If
only I were conversant enough with the system to know how to do it. What
you're telling me is rather along the lines of, "To get to New York
City, what you want to do is go to Philadelphia and then turn left." I
can see from a map of the U.S. that you're quite correct, but the
likelihood that I'll get lost somewhere in Indiana and wind up in Iowa,
tearing out my hair and annoying the natives, is quite high.
> To do this, you'll probably need to borrow some stuff about digging
> into the multiple object list from the recipe book section "Commands >
> Actions on Multiple Objects".
Chapter 20.6 of the manual implies (without quite saying it) that the
multiple object list is only used when the player uses the word "all".
Much the same process seems to be implied in RB 6.14. I'm not seeing any
indication there of what sort of list might be set up in response to a
command like 'give the apple, the pomegranate, and the rabid gerbil to
the duchess'.
If indeed any list at all would be set up. If the library give/show
actions were altered to allow multiple objects (which I don't know how
to do either), for all I know the parser would then generate three
separate actions.
Right now I'm in Iowa. Or maybe Missouri. Sorry.
Does anybody want to collaborate on writing a nice game in Inform 7?
It's 95% finished -- all except for some of the boring stuff, a few
things that are, if not impossible well beyond me, and weeks of
processing beta-test reports.
--JA
It's really no harder to mess with the scoping rules here, either --
you've already done so.
That said, another approach might be to treat your penny collective as
a notional object that responds with information about the number of
pennies regardless of how many the player has at the moment; something
like
<code>
The Candy Store is a room. The card table is in the Candy Store.
A penny is a kind of thing. It is usually privately-named. The
description is "A shiny copper penny."
Understand "copper" and "coin" and "shiny" and "penny" as a penny. One
penny is on the card table. Understand "coins" and "pennies" as the
plural of penny when the penny collective is not visible.
The player carries two pennies.
The penny collective is a privately-named thing. Understand "coins"
and "pennies" as the penny collective. The description is "[if the
player carries no pennies]You are completely penniless.[otherwise if
the player carries exactly one penny]You only have a single penny.
[otherwise]You've got [the number of pennies carried by the player in
words] shiny copper pennies.[end if]"
After deciding the scope of the player:
place the penny collective in scope.
The Store Lady is a woman in the Candy Store.
Procedural rule for giving or showing the penny collective to
someone:
ignore the basic accessibility rule;
ignore the carrying requirements rule.
Instead of giving the penny collective to the Store Lady when the
number of pennies carried by the player is less than three:
say "You're still shy a penny[if the player carries exactly one
penny] or two[end if]."
Instead of giving the penny collective to the Store Lady when the
number of pennies carried by the player is at least three:
now every penny carried by the player is carried by the Store Lady;
say "'Thanks, dear,' she mutters absently, while continuing to
contemplate Mr. October in 'Confectioners Unenrobed: 2008.'"
Test me with "drop penny / i / x pennies / give pennies to lady / get
penny / i / x pennies / give pennies to lady / get penny / give
pennies to lady / x pennies / i".
</code>
Yes, okay. I can see that this isn't nearly clear enough.
Here is a draft explanation of what goes on with multiple-action
commands:
=====
To create an action that uses multiples, or to allow the use of
multiple objects with an already-existing action, we need to create an
understand statement that uses the "[things]" token (note plural).
Such as:
Understand "give [things] to [someone]" as giving it to.
This would let the existing give action apply to multiple objects, in
just the same way that "take" does. Alternatively, we could generate a
new action:
Understand "give [things] to [someone]" as multiply-giving it to.
Multiply-giving it to is an action applying to one carried thing and
one thing.
(In theory the language here should perhaps be "several carried
things" -- but Inform is still going to process multiply-giving item
by item, unless we redirect it. Creating a separate action gives us
greater freedom to perform such redirection. More about this in a
moment.)
When handling an action that uses the "[things]" token, the parser
makes a list of every item to which it is going to apply the action:
this is called the multiple objects list. The multiple objects list
can be the result of a vague request (GET ALL) or a specific one
involving identical multiples (GET PENNIES, GET THREE APPLES) or a
very specific one involving unique, named nouns (GET GERBIL, APPLE,
AND POMEGRANATE). The first of these situations is demonstrated in
"Formicidae"; the third, in the rather more challenging "Left Hand of
Autumn" example.
A slightly tedious technical note: the multiple objects list is not
strictly a list in the standard Inform sense, because it is used so
frequently in parsing that it would be cumbersome to handle it with
the more flexible but less efficient structure used for lists.
However, if we want to manipulate the multiple objects list as though
it were an ordinary list -- that is, sort it, rotate it, truncate it,
remove entries from it, etc -- we may do so by creating a list like
this:
let L be the multiple object list.
and later after making L conform to our desires:
alter the multiple object list to L.
Inform next runs the action rulebook for the action generated, using
each item from the multiple object list as "noun" in turn (or as
"second noun", if that's where the [things] token appeared in the
understand line). Because it is possible to alter the multiple object
list before the "generate action rule" portion of the turn sequence
consults the rulebooks, we can also affect the order in which the
player's matched objects are handled; see "Formicidae". We should not
attempt to change the multiple object list after the "generate action
rule" (and, in particular, not during the actual processing of the
action rules), because this is likely to introduce bugs.
Each time Inform tries the action on a new noun, it prefixes the
action-attempt with the name of the item it's currently working on.
This is where we get such output as "frog eyeballs:" and "newt toes:"
in long lists like
frog eyeballs: Taken.
newt toes: Taken.
These names are generated by the "announce items from multiple object
lists rule" in the action-handling rules; the example "Escape from the
Seraglio" discusses how to alter them. Should we wish to write a
variant of this rule, the thing whose name we are currently printing
can be referred to as "the current item from the multiple objects
list".
Suppressing names of objects entirely, while occasionally tempting,
may have unintended consequences in the output, especially if *some*
of the attempted actions are prevented by check rules that themselves
print things. It is safest to suppress the multiple object names in
the case where we already know that the action will succeed wherever
it is attempted (more often for observational actions like examining
than for manipulative actions like taking).
Given that our hypothetical "multiply-giving" applies to each given
object in turn, it might seem to be useless to create "multiply-
giving" as an action different from "giving" -- but the convenience is
that manipulating the multiple object list makes it possible to group
behavior artificially.
=====
In the particular case you're talking about, I would direct "give
[things] to [someone]" to its own multiply-giving action, use the
multiple item list to check what the player is trying to give, and
write check rules to prohibit the action if it is not the sort of
thing we want to do.
The following is a generalized and anonymized approach to your
scenario (here, the player can offer any combination of items he is
holding, and their total worth will be considered and rejected if
insufficient). I realize this is slightly overkill, but I wanted to
try writing something that could serve as a future manual example. To
wit:
"The Facts Were These"
Section 1 - Procedure
Include Plurality by Emily Short.
A price is a kind of value. $10 specifies a price. A thing has a
price.
[Now we're going to create an action that applies to multiple objects,
but will in fact test the whole object collection during the first
pass and print a definitive answer to whether that action has
succeeded, without multiple passes. "Already gave at the office" is
the perhaps-excessively-named flag that keeps track of whether we've
already done this action once.]
Understand "give [things preferably held] to [someone]" as multiply-
giving it to. multiply-giving it to is an action applying to two
things.
Already gave at the office is a truth state that varies.
Before reading a command:
now already gave at the office is false.
First check multiply-giving it to:
if already gave at the office is true:
stop the action.
Check multiply-giving it to:
if the second noun is the player:
now already gave at the office is true;
say "You can hardly bribe yourself.[paragraph break]" instead;
let L be the multiple object list;
let bribe-price be $0;
repeat with item running through L:
if the player does not carry the item:
now already gave at the office is true;
say "You can't include [the item] in your bribe, since you're not
holding [it-them]![paragraph break]" instead;
increase bribe-price by the price of item;
if the bribe-price is less than the price of the second noun:
now already gave at the office is true;
say "[The second noun] angrily rejects your piffling bribe.
[paragraph break]" instead.
Carry out multiply-giving it to:
let L be the multiple object list;
repeat with item running through L:
now the second noun carries the item;
now already gave at the office is true;
Report multiply-giving it to:
say "[The second noun] rather shamefacedly tucks your bribe away into
a pocket.[paragraph break]"
[And since we don't want to list the individual objects separately:]
The selectively announce items from multiple object lists rule is
listed instead of the announce items from multiple object lists rule
in the action-processing rules.
This is the selectively announce items from multiple object lists
rule:
if multiply-giving:
do nothing;
otherwise:
if the current item from the multiple object list is not nothing:
say "[current item from the multiple object list]: [run paragraph
on]".
[And now, since this ought to work symmetrically if the player
provides just one high-value item:]
Check giving something to someone:
if the price of the noun is less than the price of the second noun:
say "[The second noun] angrily rejects your piffling bribe."
instead.
The block giving rule is not listed in any rulebook.
The new report giving rule is listed instead of the standard report
giving rule in the report giving it to rules.
This is the new report giving rule:
say "[The second noun] rather shamefacedly tucks your bribe away into
a pocket."
Section 2 - Scenario
The Morgue Office is a room. The Morgue Attendant is a man in the
Morgue Office. The price of the Morgue Attendant is $3.
A dollar is a kind of thing. The player carries three dollars. The
price of a dollar is always $1.
The player carries a rhubarb pie. The price of the rhubarb pie is $5.
The player carries a knitted cap. The price of the knitted cap is
$2.
Test me with "drop all / give dollars to Morgue Attendant / get
dollar / give dollar to Morgue Attendant / get dollar / i / give
dollars to Morgue Attendant / give dollars to dollar / give dollars to
me / get dollar / give dollars to Morgue Attendant".
Test largesse with "give pie to Morgue Attendant".
Test mixed-gift with "give dollar and cap to Morgue Attendant".
=====
If there is other stuff you're finding maddeningly under-documented, I
might have some time to help you out with coding it in a few weeks, in
exchange for feedback on how best to improve the manual coverage of
those items. On the other hand, possibly someone else can offer more
immediate assistance.
Because, yowza.
--JA
Sure.
For what it's worth, I did some more work on this today in preparation
to include it as a future example; it will be in the new build, but
for now the revised form can be found here:
http://emshort.home.mindspring.com/FactsWereThese.txt
It adds more commentary to the original, gives better feedback if the
player tries to give an object that isn't appropriate, and handles
implicit takes for objects that might need to be given.
I don't actually think I'm a stupid person, but there are times when I
think I may understand how stupid people must feel, trying to get along
in the world -- and this is one of them.
I pretty much don't understand _anything_ in your FactsWereThese file.
I'm sure if I were to run the example as given, it would work. The
problem is, I can't even begin to grasp how to customize its code in
order to do what I need to do. Nor can I see how the algorithm you've
designed operates.
"Check multiply-giving it to: let L be the multiple object list; let
bribe-price be $0; repeat with item running through L: if the player
does not carry the item: abide by the ungivability rules for the
item...." Aaackkk!!!
I don't want to build a skyscraper, honestly I don't. All I want to do
is let the player give exactly three indistinguishable objects to an NPC
with a single command, and without the parser issuing a misleading error
message if the player tries to do it while holding only one or two of them.
Part of the problem, I think, may be that I7 insists that it knows the
proper way to construct plurals of nouns. It knows the plural of penny
is "pennies" even though I haven't specified that in my code. And this
is wrong-wrong-wrong. It's something that an IF language should NEVER
do. If I want to deflect the word "pennies" exclusively onto my own
plural-pennies object, so that I can write my own code for handling that
object, I should be able to do so. But I can't. I tried "Understand
"pennies" as something new," but the compiler doesn't like that. When my
plural-pennies object is in scope, and a single penny object is also in
scope, the noun 'pennies' is understood by the parser as applying to the
single penny, NOT to my plural-pennies object. I tested this. That's
what happens.
Of course, it's entirely possible that using a plural-pennies object
wouldn't get me where I want to go, though it would certainly work in I6
or T3. But that's the first thing I thought I'd try.
Here, as well as I can nail it down, are the criteria I'm dealing with:
1) There are three indistinguishable penny objects in the game.
2) The player can be carrying, directly or indirectly (in a container),
any combination of the pennies. Or they might be in the room, or on a
supporter in the room, or in a closed container, etc. They might be
anywhere. The player might try to refer to them while _none_ of them are
in scope.
3) The player needs to be able to 'give pennies to npc' as a single
action, but only while having access, directly or indirectly, to all
three. That is, one might be held and two in an open container carried
by the player. In that case, all three should be handed over to the npc,
with no muss and no fuss. (Actually, they should be removed from play,
because we're done with them at that point.)
4) If the player is has access to only two pennies, the parser should
not respond to 'give pennies to npc' with, "You can't use multiple
objects with that verb." By default, if the player tries 'give the
toadstool and the rabid gerbil to the npc', the response should be,
"Generally speaking, you can't use multiple objects with that verb."
This is a simple rewrite, and it avoids being misleading. So I'd like to
replace that library message with my own.
5) If the player tries to give two pennies, the npc needs to know it and
issue an appropriate "You don't have enough money" message.
6) In no other situation in the game do multiple objects need to be
given or shown with a single command, so constructing a general-purpose
multiple-giving action would almost certainly cause all sorts of messy
stuff that I don't want.
7) I'm using, and want to continue to use, Eric's conversation
extensions to handle the giving and showing actions.
My first-level question is, how exactly would I do that?
My second-level question is, why is Inform 7 code (as seen in the
FactsWereThese example) so mind-numbingly difficult to understand? For
example, "This is the selectively announce items from multiple objects
list rule: if multiply-giving...."
I can see two reasons. First, I7 code consists of great clotted clumps
of nouns, verbs, adjectives, adverbs, and prepositions, all strung
together in a word salad that only vaguely resembles English. Brackets
and equals-signs would be MUCH easier to read. Second, each rule in I7
is a sort of free-floating entity rather than being inserted in an
orderly way in a larger block of code (a method or function). True, you
can use first, last, before, and after to _attempt_ to create some sort
of quasi-order in a rulebook, but you don't actually get to _look_ at
the rulebook; you have to cross your fingers and hope you did it right.
Even figuring out what rulebook a given rule will be tucked into by the
compiler is not so easy, is it?
On top of which, I7 seems (from all I've seen) to have no way to pass
values to functions as arguments. All of the values you're working with
are global. That seems to contribute to the word salad effect as well,
and also to the code-strung-out-everywhere effect.
I've been hoping to have this game ready for the Spring Thing. But right
now I'm perilously close to saying, "Fuck it. I'll rewrite it in a
decent language (i.e., TADS 3) and submit it next year."
I really have been giving I7 the old college try here. The game is about
95% done, and I've learned to do all of the standard things pretty
smoothly. But it's that last 5% that's killing me -- this problem and
also the giving-things-you're-not-holding problem, plus probably three
or four other little snarfles that testers will stumble upon.
Inform 7 seems actively to want to crush my creative spirit. I don't
like to say that; I'd _like_ to feel that it's a wonderful step forward
in IF authoring. But as they used to say on TV, "Sorry, Charlie --
StarKist only wants tuna that taste good."
--JA
I don't want to add to your troubles, but that is also a misleading
message. How many pennies the player tries to give and how much money
the player has are two separate issues. If the player is trying to give
the npc three pennies, it would be perfectly reasonable to do it by:
"Give penny. Give penny. Give penny." Being told that you don't have
enough money while trying to do that would be quite unfortunate.
> I've been hoping to have this game ready for the Spring Thing. But right
> now I'm perilously close to saying, "Fuck it. I'll rewrite it in a
> decent language (i.e., TADS 3) and submit it next year."
Don't give up. I know that Inform 7 is a complex language, but I'm sure
it's not rocket science. You just need to take it slowly and carefully;
think through everything that you read and don't let yourself get
overwhelmed. Eventually you'll figure out everything that is mysterious
about Inform 7 and that will be enormously rewarding. You've gone too
far down the hard path to go back and take the easy way.
>> I've been hoping to have this game ready for the Spring Thing. But right
>> now I'm perilously close to saying, "Fuck it. I'll rewrite it in a
>> decent language (i.e., TADS 3) and submit it next year."
>
> Don't give up. I know that Inform 7 is a complex language, but I'm sure
> it's not rocket science. You just need to take it slowly and carefully;
> think through everything that you read and don't let yourself get
> overwhelmed. Eventually you'll figure out everything that is mysterious
> about Inform 7 and that will be enormously rewarding. You've gone too
> far down the hard path to go back and take the easy way.
Thanks for your encouragement (I think). Whether it will ever be
enormously rewarding ... well, maybe in the sense that it's enormously
rewarding when you stop banging your head against a brick wall.
No, it's not rocket science. It isn't even as complex as T3. The problem
is that it isn't _clear_. For starters, there is no manual. There's a
great big wonderful tutorial ... but there's no manual. Then there's the
design philosophy, which is that rules are these free-floating entities
that the compiler will tuck into rulebooks (i.e., ordered code blocks)
for you, so you never have to worry about it. Except that you do have to
worry about it, except that when you start worrying about it you're on
your own, because the library rulebooks can't be opened and viewed. Then
there's the fact that the handy 'rules all' utility command DOESN'T LIST
ALL OF THE RULES THAT ARE RUNNING. And since there's no debugger, you
can't step through the code and try to figure out what's going on. Then
there's the fact that I7 automatically creates plurals of nouns without
letting the author disable the plurals. Then there's the fact that the
language doesn't include functions that can be called with arguments and
return values: Everything is global. And there are no braces, no dot
operators, no equals signs, so the code is not only disorganized, it's
also unnecessarily verbose and hard to read.
It's not that I always know how to do stuff in T3: I don't! I often have
to ask questions. But I always have the sense that the answer will
become clear before too very long if I keep at it, because the entire
library can be opened up and inspected, line by line, in the Workbench.
I _can_ keep at it, because there's always an answer to "what can I try
next?"
That is emphatically _not_ the case in I7. I do not have the sense that
I will ever be able to understand it, because, at bottom, the syntax is
muddled and the library is opaque. All I can do is wait for Emily to
post an answer on the newsgroup -- and if, as happened in this case, I
don't understand the answer, I'm screwed, because there is no "what can
I try next?"
--JA
> No, it's not rocket science. It isn't even as complex as T3. The problem
> is that it isn't _clear_. For starters, there is no manual. There's a
> great big wonderful tutorial ... but there's no manual. Then there's the
> design philosophy, which is that rules are these free-floating entities
> that the compiler will tuck into rulebooks (i.e., ordered code blocks)
> for you, so you never have to worry about it. Except that you do have to
> worry about it, except that when you start worrying about it you're on
> your own, because the library rulebooks can't be opened and viewed.
I'm not sure I understand this complaint. The Standard Rules can be
read, either by opening up your own Inform package and looking at
them, or by reading the typeset versions on the website. Generated
rulebooks can be examined in the indices (in the actions index if
they're for actions, and in the rules index if they're for rules).
This shows you the order in which rules are arranged, and if you hover
your mouse over the little arrow that leads from one rule to the next,
it will pop up a tooltip explaining on what basis Inform made the
ordering decision.
> Then
> there's the fact that the handy 'rules all' utility command DOESN'T LIST
> ALL OF THE RULES THAT ARE RUNNING.
Yeah -- there are reasons why it seemed a good idea not to list the
very lowlevel, always-on rules that are coded in Inform 6, as opposed
to the I7-implemented rules that people are usually meddling with (or
writing themselves).
We've talked about this, and I've added an item to the wishlist
concerning it. We will see.
> And since there's no debugger, you
> can't step through the code and try to figure out what's going on. Then
> there's the fact that I7 automatically creates plurals of nouns without
> letting the author disable the plurals. Then there's the fact that the
> language doesn't include functions that can be called with arguments and
> return values: Everything is global.
That's not the case. Phrases take arguments. Activities and object-
based rules take arguments.
Anyway, I'm not trying to convince you to do anything, and you're
welcome to form whatever conclusions you like, of course.
Okay, sorry. I was responding to the implication I thought I detected
in your earlier post, to the effect that you thought the revised
parser message ("In general, you can't use multiple objects...") to be
a bit of a hack, and that you wanted to manage the response more
elegantly, and for there to be better documentation on how to handle
actions that take multiple objects. (Did you find the documentation of
that which I posted to be understandable?)
If you want, it should be possible to do all this stuff with the penny
collective, and in fact you've already solved a number of the issues
that play into that. The next steps are, I think, these:
-- make the penny collective be in scope at all times, and provide
sensible responses to EXAMINE PENNIES and GIVE PENNIES regardless of
how many the player holds; but defer to the individual objects except
when giving/showing or examining. Making it be in scope at all times
is easy -- you just yank out the condition in your place in scope rule
so that it *always* applies, and then write some responses for EXAMINE
PENNIES and GIVE PENNIES depending on how many the player has at the
moment. The hardest part will probably be the last bit of that
sentence ("but defer..."), because you still want TAKE PENNIES, DROP
PENNIES, etc., to act on the separate pennies. This is doable too, and
is the piece not included in the sample code I posted in this thread
Dec. 28; there are a couple of ways to go about it, but I'm not going
to recommend one right this second until I've given it some more
thought and can offer you working code.
-- replace the default message about multiple objects. To do that, I'd
use one of Fisher's library extensions (if you aren't already), and
search for the text that you want to replace. I think (from looking)
that what you want is something like
Include Default Messages by David Fisher.
Table of custom library messages (continued)
Message Id Message Text
LibMsg <verb cannot have multiple objects> "In general, you can't use
multiple objects with that verb.[line break]"
-- override the player-must-be-holding requirement in giving and
showing, which we've also discussed how to do: a procedural rule to
lift the carrying requirements in general, and also to remove the
check rules from giving and showing. (For what it's worth, I've also
amended the recipe book's discussion of these issues a good bit, in
the hope that other people won't find this so confusing.)
-- test the compatibility of the results with Eric's extension, which
I also haven't had time to do yet. But I *suspect* this won't be too
huge an issue, and that the problems lie earlier on.
That's a pretty small reward. Actually, the real reward will come if you
stick with it and do not give up. I'm sure there is a way in which you
can master Inform 7, and being a master of Inform 7 is your reward, just
like the feeling of accomplishment that you get from doing anything that
is difficult to do. To modify your analogy, your reward is breaking down
the wall.
> No, it's not rocket science. It isn't even as complex as T3. The problem
> is that it isn't _clear_.
The relative complexity of Inform 7 and TADS 3 depends upon how you look
at it. The great thing about TADS 3 is that its syntax is enormously
simpler. Understanding all the keywords and operators of TADS 3 is
childs play compared to learning every last bit of natural language
syntax of Inform 7.
On the other hand, TADS 3 starts getting hugely complex if you go beyond
the syntax and into the library. As I've heard, the TADS 3 library is
huge compared to the Inform 7 library. Even so, the complexity of the
library really doesn't matter until you've at least mastered the syntax
of the language. When you know the syntax with total confidence like
anyone can with TADS 3, understanding the library is simply a matter of
exploring it.
> For starters, there is no manual. There's a great big wonderful tutorial
> ... but there's no manual.
TADS 3 has a ton of manuals mostly thanks to the amazing Eric Eve, but
even so there are obscure bits of the library that are mostly
undocumented. To really understand TADS 3 or Inform 7, I think you've
got to first master the language, then study the library with your own
eyes.
> Except that you do have to worry about it, except that when you start
> worrying about it you're on your own, because the library rulebooks can't
> be opened and viewed.
I recommend that you start by making sure you know everything that the
tutorial has to offer about rules and rulebooks. I'm sure you've read it
all, but you should make sure you haven't forgotten anything. Once
you've done that, then learn the rest by experimentation; just play with
rules on a trivial game until you've got perfect intuition about what
goes into the rulebooks.
> Then there's the fact that I7 automatically creates plurals of nouns without
> letting the author disable the plurals.
That's annoying, but I can forgive Inform 7 for it. After all, it is
really just doing the right thing. You should try to work within the
system instead of fighting it. If you give the system pennies then you
shouldn't complain when it uses the word 'pennies' to refer to the
pennies.
<perk>
[eyes slide left, toward the ubiquitious brick wall, and slowly focus
on it, focus getting a little better with each impact, focus ...
focus ...]
[momentarily *stops* banging head against the brick wall]
[pauses to consider how it feels]
holy crap ...
Holy. Crap. HOLY CRAP! THIS IS GREAT.
[bangs head against brick wall *one more time* just to make *sure*
this rush of pleasant feeling wasn't just a coincidence]
Oh, this is SO going to help my WIP.
>> Except that you do have to
>> worry about it, except that when you start worrying about it you're on
>> your own, because the library rulebooks can't be opened and viewed.
>
> I'm not sure I understand this complaint. The Standard Rules can be
> read, either by opening up your own Inform package and looking at
> them, or by reading the typeset versions on the website.
I don't understand. I'm looking at the Windows IDE right now. Is that
the "Inform package" you're talking about? If so, where is the I7
equivalent of the entire line-by-line TADS library code? In the Rules
pane of the Index I find a long list of rules, most of which are in my
source code. Near the bottom of the page is a list of rules that aren't
from my source code -- the basic accessibility rule is as good an
example as any. But the text of the rules is not stated, and there are
no links to any pages where the text of the rules is set forth. Nor do I
see anything that would tell me when or why these rulebooks run (in
relation to other rulebooks).
There are also rules in the Actions Index. For example, I can click on
the magnifying glass button next to "attack [something]". Here I find a
list of "Rules controlling this action" ... but the text of none of the
rules is listed, and there are no links to any code in which the text
might be listed.
So, in what sense can the Standard Rules be read? What am I missing?
>> Then there's the fact that the
>> language doesn't include functions that can be called with arguments and
>> return values: Everything is global.
>
> That's not the case. Phrases take arguments. Activities and object-
> based rules take arguments.
Searching the documentation for the word "argument" doesn't take me
anywhere, but that's not surprising, as it's purely a matter of
nomenclature, and I7 can quite legitimately use its own nomenclature
(though it would be nice if the manual mentioned the equivalents that
are found in standard nomenclature -- but never mind). So I look at the
chapter on phrases, since you mentioned phrases. What I'm looking for is
a section called, perhaps, "Phrases that return values to the code that
invoked them." I can't find it.
"Phrases to decide other things"? No, that isn't the right page. Okay,
I'm stumped. Where is the page that tells me how to send an argument to
a phrase, or better still, three or four of them (in precisely the way I
would arguments to a function or a method) and get a return value out of
it after it runs? Not using global variables, mind you -- using actual
arguments and return values.
> Anyway, I'm not trying to convince you to do anything, and you're
> welcome to form whatever conclusions you like, of course.
Well, I actually do wish you'd try to convince me, and not because I'm
being contrary. Right now I have some home-school kids who _want_ to
learn to write IF, who are eager to start, who will pay me to teach them
(!), and I'd _like_ to steer them to I7, because I'm pretty darn sure
they'll find it easier to grasp than T3. But right now I don't think I
could do that, in good conscience ... not only because I wouldn't know
how to answer their questions on topics like these, but because I don't
want them to end up as frustrated and disappointed as I am.
This is a legitimate issue, I think. And it's not just because I'm an
ornery old coot who doesn't always follow the trail of breadcrumbs
(though I am that). It's because of the way the language, the library,
and the IDE are designed. If these designs will do what I need them to
do, please tell me how!
--JA
No, that's not correct. In principle, the author MUST be able to control
EVERY feature of the system with respect to text input, internal logic,
and text output. A system that does not allow the author to do that is
not mature, and the serious writer will be wise to avoid investing time
in learning it -- because sooner or later you're going to end up banging
your head against the friggin' wall.
Another word for it is "arrogance." The system (in this case, I7) is
being arrogant. It seems to be asserting (unless somebody tells me how
to override the default behavior) that it knows better than the writer
what is needed. That's not acceptable, not even in a little tiny detail
like forming plurals.
I don't mind writing my own code to undo the system's default behavior.
That's expected. But I do insist that the hooks with which to override
ANY default behavior be (a) provided and (b) documented.
--JA
Hm.
> I don't understand. I'm looking at the Windows IDE right now.
The Standard Rules are an extension, in the Graham Nelson folder (in
the Extensions folder).
But in truth, I wish it had it's own tab within the IDE, too. Even
just having the _names_ of the rules with a quick summary, within the
IDE, would often be helpful. If I get to a point in a design where it
might be wise to fiddle with (to pick one literally at random) the
"iinvestigate player's awareness before action rule," there's no real
hint within the IDE to guide me toward that, unless an example happens
to deal with it directly, and no way to guess what the exact name of
any given rule might be (even though they're unassailable logical
names, they're by no means _inevitable_ names) :)
That also said, I7 is still in Beta, and I think it's always good to
bear that in mind. It would be wasteful to document it too deeply
until the guts settle a bit more, IMO.
That said, I'm no computer guy, so what do I know?
I don't know enough about Windows to tell you how to look at this, but
on the Mac I have an Inform application. If I command-click on it, I
can choose to view the contents of that application package; the
Standard Rules are among the files inside. (It does, I admit, take a
little scrounging around -- the directory path is Contents/Resources/
Inform 7/Extensions/Graham Nelson.)
This is not very accessible, I know, and easier Standard-Rules access
is on the outstanding list of things we mean to work on. Meanwhile,
the rules (albeit from 5T18) *are* also in PDF form, with comments,
here:
http://www.inform-fiction.org/I7/Download%20-%20Documents.html
and beside them is a documented copy of the template layer. The
comments contain a great deal of detail on things like the turn
sequence, the generation of actions, and so on, and as these features
haven't changed much in the latest build, the PDF will probably
suffice to explain them.
The Standard Rules are written in Inform 7, though with hooks into
Inform 6; the template layer is almost all pure I6, and it contains
the innards of the parser and many other bits and pieces (though not
the action logic, for the most part, which has been rewritten into
I7).
The ultimate intention of this (still not totally complete) design is
to selectively occlude the complexity without in practice making
anything inaccessible to someone who wants to understand or change it.
Earlier versions of I7 did make certain parts of the system impossible
to change, but that wasn't part of a design philosophy, and personally
I always found it very troubling. In the current system, if you want
to, you can replace any portion of the Standard Rules -- or any of the
I6 template files -- with your own, or instruct the compilation to
include new material between compiling one template file and the next,
or omit sections. The Extensions section of the documentation outlines
how this can be done.
In practice, what that means is that an interested and determined
party can modify quite a lot of the content on a very deep level --
Jesse McGrew is probably the person who has made the most practical
use of this in adapting Inform for Textfyre and also writing the
Guncho modules to generate real-time, multiplayer IF. One could, if
one liked, write an extension that would have the power to strip down
the Standard Rules to a minimum, or indeed to replace major parser
features. This would be a lot of work, but the possibility exists, and
a few die-hards have made use of it.
> > That's not the case. Phrases take arguments. Activities and object-
> > based rules take arguments.
> "Phrases to decide other things"? No, that isn't the right page.
> Okay,
> I'm stumped. Where is the page that tells me how to send an argument to
> a phrase, or better still, three or four of them (in precisely the way I
> would arguments to a function or a method) and get a return value out of
> it after it runs? Not using global variables, mind you -- using actual
> arguments and return values.
This information is spread out through the pages you cite, and you've
been using phrases without, perhaps, realizing that you were already
doing this. But here is how it works. If I write a phrase
To wash (chosen laundry - a thing) with (chosen soap - a detergent) in
(chosen machine - a device):
... then all of those parenthesized bits ("chosen laundry", "chosen
soap", "chosen machine") are local variables, and the portion after
the hyphen indicates the type to which the local variable is required
to belong. (Extend as needed.) I would then call this from elsewhere
in my code like so:
wash the red shirt with Tide in the rusty washing machine.
...and this would pass the arguments "red shirt", "Tide", and "rusty
washing machine" as the contents of these local variables.
Phrases that return values are those labeled "to decide". They can
exist without arguments, as in
To decide which object is the most valuable thing: ...
To decide whether acting in the dark: ...
and be called implicitly, as in
now the player carries the most valuable thing; [which would
automatically work out the identity of the most valuable thing, and
move it]
Or they can take arguments, as in
To decide which ice cream is the favorite of (chosen child - a
person): ...
in which case they can be called as in
now Betty carries the favorite of Betty.
A "to say" phrase is a special case of this in that it is allowed to
be called from within quotations, but even to say phrases can be
passed multiple arguments.
It is also possible to pass the result of one phrase to another as an
argument
say "[the time of day to the nearest five minutes in words]";
"Time of day to the nearest five minutes" is being calculated by a
phrase
To decide which time is (t - time) to the nearest (t2 - time)"
then this is being passed to the say phrase
To say (something - time) in words: ...
So that from a more conventional programming point of view this might
be pseudo-coded like so:
SayInWords( TimeRoundedTo( time_of_day, 5 ) );
There are two features of the Inform version that I personally find
useful. First, I rarely have the situation where I remember the name
of the function but not the order in which the arguments should be
supplied (because the way the phrase is constructed tells you whether
you list the Tide first or the rusty washing machine); whereas I am
constantly having to look up the order of arguments for, e.g., obscure
Glulx routines whenever I need to use these.
Second, because of the way the typing works, it is possible to write
To remove points from (character - a person):
and then selectively override it, under the right circumstances, with
To remove points from (character - Joe):
where the latter phrase applies only when Joe is the character.
My mind obviously works quite a bit differently from yours, so I have
no expectations about whether you will also find these things
advantageous. I can see that there is conversely the disadvantage that
Inform's version does not make as clear which pieces of code are part
of the phrase and which name an object or variable, and I can
understand why for some people that might be very frustrating, though
it is not something I personally have difficulty with. On the
contrary, I find that this (and several other) aspects of Inform
encourage me to think about design by focusing first on the general
shape of what I want to achieve and then fill in the pieces. I am sure
it is possible to design and code that way in other, more typical
styles of language, but the fact that I can write something that
starts as a specification and turns into executable (with a lot of
modifications, yes, but in a recognizable way) means that I tend to
prototype more thoughtfully and then to write more general, more
maintainable code. I think of this a bit like writing the outline of
an essay or story and then filling it in -- and in fact I often use
section headings this way in large projects, creating a lot of
sections for the functionality I know I will need and then writing it
into place later. Far from feeling disorganized (and I'm sure it does
for some people), this process corresponds closely to my process for
writing large non-fictional works where I know I will need to check a
reference here, revise my organization there, etc., before the whole
argument will become viable, but I nonetheless have the shape of the
whole thing in my head.
All that said, I also know my experience with the language is unlike
anyone else's.
Though I've explained phrases in more (and more computery) detail than
the manual does, the essentials are introduced early in the Phrases
chapter (under "Pattern Matching"); the general method of using such
phrases is demonstrated in more examples than I can name, and gone
over in the chapter summary at the end of the Phrases chapter. For
example, the following are all listed as possible phrase headings:
To empty the player's luggage: ...
To remove points from (character - a person): ...
To remove (point value - a number) points from (character - a
person): ...
To make (character - a person) lose (point value - a number) points in
the eyes of (voter - a person): ...
...which certainly shows off multiple arguments. The syntax document
also has a number of sample patterns under "Phrases" and "To decide"
and "To say".
Beyond the realm of phrases, it is also possible to make rulebooks
that pertain to (single) objects (look under Action vs Object-based
rulebooks in the rulebooks chapter) and to have local variables
confined in scope to a given iteration of an action, or to a given
rulebook. (See Advanced Actions > Action Variables, Rulebooks >
Rulebook Variables.)
If your question is why, in the particular example I just wrote, I
used global variables, the reason is the same reason I would have had
to do so in Inform 6. (Though on consideration I suspect this would
have been considerably harder to do in I6: to implement this kind of
action in the standard I6 library would require aggressive parser
hacking because of the relative lack of access to multiple-object
internals there.) Anyway, we're repeatedly processing an action, and
on multiple objects, so we *need* a variable whose contents will
persist beyond the individual iterations of the action, and which is
not associated with any given object.
There is plainly also a desire for a computer-programmer-oriented
documentation of Inform, which would really need to be a different
document from the current one; too many goals for a given writing
project guarantee it will be incomprehensible to everyone. I note that
a couple of other people have begun such documentation projects, and
wish them well.
There are several problems with this code. Here's the output:
>[1] give pennies to bob
(the penny to Bob)
Bob does not respond.
>[2] take pennies
penny: Taken.
penny: Taken.
penny-collective: That isn't available.
>[3] give pennies to bob
In general, you can't use multiple objects with that verb.
>[4] give coins to bob
That isn't available.
>[5] drop coins
You drop the 3 pennies.
Command 5 works as expected, showing that it's possible to use the
penny-collective for handling individual objects. But it works only
because I'm using the word "coins", not the word "pennies". (The latter
would produce three separate "Dropped." outputs, each on its own line.)
Command 1 fails in two ways -- it doesn't make use of the
penny-collective object, as it ought to do, and it also doesn't produce
the response of Bob when given-or-shown a random penny. Command 2
produces an extra line of output for the penny-collective, which is
nasty, and I would have no idea how to circumvent it. Commands 3 and 4
fail in complementary ways: The "pennies" word is routed to the
individual objects, not to the penny-collective. And the "coins" word
refuses to see the penny-collective, even though it has been added to
scope. Or possibly this is happening because the procedural rules aren't
working.
The desired output (which may or may not be obvious) is this:
>[1] give pennies to bob
(the penny to Bob)
"The payoff is three cents, bud. Don't get me mad."
>[2] take pennies
penny: Taken.
penny: Taken.
>[3] give pennies to bob
"Thanks for the payoff," Bob says. "Now I won't have to kill you."
>i
You are empty-handed.
How can I produce the desired output?
--JA
[code]
Include Conversation Framework by Eric Eve.
Include Conversation Responses by Eric Eve.
Include Conversational Defaults by Eric Eve.
Include Plurality by Emily Short.
Include Default Messages by David Fisher.
Table of custom library messages (continued)
Message Id Message Text
LibMsg <verb cannot have multiple objects> "In general, you can't use
multiple objects with that verb.[line break]"
The Test Lab is a room. "Various tests are carried out here."
A penny is a kind of thing. The description is "A shiny copper penny."
Understand "shiny", "copper", "coin", and "cent" as a penny.
The penny-collective is a privately-named thing. Understand "coins",
"cents", "pennies", and "pence" as the penny-collective. The description
is "Three shiny copper pennies."
After deciding the scope of the player:
place the penny-collective in scope.
[This next block of code works -- but not if the player uses the word
'pennies', because that's reserved by I7 as the plural of the penny
objects.]
Before dropping the penny-collective:
let N be a number;
now N is 0;
let P be a random penny carried by the player;
if P is not a thing:
say "You aren't carrying any pennies.";
stop the action;
otherwise:
silently try dropping P;
increase N by 1;
let P be a random penny carried by the player;
if P is a thing:
silently try dropping P;
increase N by 1;
let P be a random penny carried by the player;
if P is a thing:
silently try dropping P;
increase N by 1;
say "You drop the ";
if N is 1:
say "penny.";
stop the action;
otherwise:
say "[N] pennies.";
stop the action.
The table is a supporter in the Test Lab. Two pennies are on the table.
The player carries one penny.
Bob is a man in the Test Lab.
A procedural rule when giving or showing the penny-collective to Bob:
ignore the carrying requirements rule.
A procedural rule when giving or showing the penny-collective to Bob:
ignore the can't give what you haven't got rule;
ignore the can't show what you haven't got rule.
Response of Bob when given-or-shown the penny-collective:
if the player carries three pennies:
let P be a random penny carried by the player;
remove P from play;
let P be a random penny carried by the player;
remove P from play;
let P be a random penny carried by the player;
remove P from play;
say "'Thanks for the payoff,' Bob says. 'Now I won't have to kill you.'";
otherwise:
say "'You're comin['] up short,' Bob complains. 'I need three cents.'"
Response of Bob when given-or-shown a random penny:
say "'The payoff is three cents, bud. Don't get me mad.'"
test me with "give pennies to bob / take pennies / give pennies to bob /
give coins to bob / drop coins"
[/code]
>Part of the problem, I think, may be that I7 insists that it knows the
>proper way to construct plurals of nouns. It knows the plural of penny
>is "pennies" even though I haven't specified that in my code. And this
>is wrong-wrong-wrong. It's something that an IF language should NEVER
>do. If I want to deflect the word "pennies" exclusively onto my own
>plural-pennies object, so that I can write my own code for handling that
>object, I should be able to do so. But I can't. I tried "Understand
>"pennies" as something new," but the compiler doesn't like that. When my
>plural-pennies object is in scope, and a single penny object is also in
>scope, the noun 'pennies' is understood by the parser as applying to the
>single penny, NOT to my plural-pennies object. I tested this. That's
>what happens.
Did you try,
The plural of penny is YOURMOTHER ?
Adam
<code>
Include Conversation Framework by Eric Eve.
Include Conversation Responses by Eric Eve.
Include Conversational Defaults by Eric Eve.
Include Plurality by Emily Short.
Include Default Messages by David Fisher.
Table of custom library messages (continued)
Message Id Message Text
LibMsg <verb cannot have multiple objects> "In general, you can't use
multiple objects with that verb.[line break]"
The Test Lab is a room. "Various tests are carried out here."
A penny is a kind of thing. The description is "A shiny copper penny."
Understand "shiny", "copper", "coin", and "cent" as a penny.
The penny-collective is a privately-named thing. Understand "coins",
"cents", "pennies", and "pence" as the penny-collective. The
description is "[if the player carries at least two pennies]You have
[number of pennies carried by the player in words] shiny copper pennies
[otherwise if the player carries a penny]You have just one shiny penny
[otherwise]You are penniless[end if]."
After deciding the scope of the player when giving or showing or
examining:
place the penny-collective in scope.
[By restricting the penny-collective just to those verbs where we do
want to act on the pennies collectively, we avoid having to write
special rules for dropping the penny collective, taking the penny
collective, etc., which would otherwise be cumbersome and susceptible
to bugs.]
Understand "give [penny-collective] to [someone]" as giving it to.
[This solves the problem in test 1. By default, give and show prefer
things that the player is holding at the moment, so it wasn't
considering said collective.]
Understand "show [penny-collective] to [someone]" as showing it to.
Understand "examine [penny-collective]" as examining.
The table is a supporter in the Test Lab. Two pennies are on the
table.
The player carries one penny.
Bob is a man in the Test Lab.
A procedural rule when giving or showing the penny-collective to Bob:
ignore the carrying requirements rule;
ignore the basic accessibility rule;
ignore the can't give what you haven't got rule;
ignore the can't show what you haven't got rule.
Response of Bob when given-or-shown the penny-collective:
if the number of pennies carried by the player is:
-- 3:
repeat with N running from 1 to 3:
let P be a random penny carried by the player;
remove P from play;
say "'Thanks for the payoff,' Bob says. 'Now I won't have to kill
you.'";
-- 2:
say "'You're comin['] up short,' Bob complains. 'I need three
cents.'";
-- otherwise:
say "'The payoff is three cents, bud. Don't get me mad.'"
test me with "give pennies to bob / take pennies / give pennies to
bob / give coins to bob / drop coins"
</code>
For what it's worth, though I don't use this method here, you can
override the creation of the plural to make it a different plural
(viz, one the player is less likely to type). E.g.:
The plural of penny is blurgz. [That's how we override Inform's
default assumptions about plurals. It is documented at Kinds > Plural
assertions.]
Then to clean up the output:
Rule for printing the plural name of a penny:
say "pennies".
This is explained in the activities chapter.
Okay, I found it. Windows has a cute habit of putting the stuff it
thinks users should want to access in the My Documents folder (this is
where I7 extensions end up when the user adds them) and stuff it thinks
belongs to the app in the Program Files folder. In Program Files >
Inform 7 > Inform7 > Extensions > Graham Nelson, we find Standard Rules.i7x.
This file is undoubtedly useful. Or is it? Just for kicks, I searched
the file for "basic accessibility", with the idea that I'd like to
understand how the basic accessibility rules work (for no reason other
than because I happened to know the name of that rule). The string
"basic accessibility" is used exactly twice in Standard Rules -- and in
_neither_ usage is there a single line of code that would tell me how
this rule operates.
What seems to be going on is that the actual rules are in I6 code, which
is not in Standard Rules.i7x. So ... well, I guess that means that
Standard Rules.i7x doesn't contain the actual library code. The actual
rules are in the template layer or something. Standard Rules itself has
no comments, but there is indeed a good deal of highly specialized
information in the PDF files that can be downloaded.
What this means, I suppose, is that the I7 author who can't read or
write I6 simply has to take the library on faith, because there's no
clear way to hack it. In TADS 3, contrariwise, once you understand the
syntax of the language the entire library is right there. It's all
written in exactly the same type of code.
> The ultimate intention of this (still not totally complete) design is
> to selectively occlude the complexity without in practice making
> anything inaccessible to someone who wants to understand or change it.
I'm not sure what the value of "occluding complexity" might be, but I
guess Microsoft Word occludes the complexity of the 1's and 0's in
Unicode characters. That's arguably a good thing for most people, most
of the time.
> Earlier versions of I7 did make certain parts of the system impossible
> to change, but that wasn't part of a design philosophy, and personally
> I always found it very troubling. In the current system, if you want
> to, you can replace any portion of the Standard Rules -- or any of the
> I6 template files -- with your own, or instruct the compilation to
> include new material between compiling one template file and the next,
> or omit sections. The Extensions section of the documentation outlines
> how this can be done.
I'm not a hacker, though. I just want my game to work right.
> This information is spread out through the pages you cite, and you've
> been using phrases without, perhaps, realizing that you were already
> doing this. But here is how it works. If I write a phrase
>
> To wash (chosen laundry - a thing) with (chosen soap - a detergent) in
> (chosen machine - a device):
>
> ... then all of those parenthesized bits ("chosen laundry", "chosen
> soap", "chosen machine") are local variables, and the portion after
> the hyphen indicates the type to which the local variable is required
> to belong. (Extend as needed.) I would then call this from elsewhere
> in my code like so:
>
> wash the red shirt with Tide in the rusty washing machine.
>
> ...and this would pass the arguments "red shirt", "Tide", and "rusty
> washing machine" as the contents of these local variables.
Ah, I see. No, I didn't know that at all. It seems child's play once
it's explained to you, as Sherlock Holmes once remarked. Ditto for your
explanation of "to decide" phrases. If I were using any of those, I'm
sure I'd understand them better now.
> My mind obviously works quite a bit differently from yours,...
Possible but unproven. Just as possible: You've been living with this
system for three years, and know it inside out. I'm just blundering
around picking things up and dropping them, because I don't know what
key goes with what locked door.
--JA
Alas, that doesn't work. It produces output like this:
You can see a table (on which are two yourmothers) here.
--JA
...which you can also override, as I just explained.
http://groups.google.com/group/rec.arts.int-fiction/msg/b682ee7c20f9b46d
>take coins
You can't see any such thing.
I'll keep playing with it.
> For what it's worth, though I don't use this method here, you can
> override the creation of the plural to make it a different plural
> (viz, one the player is less likely to type). E.g.:
>
> The plural of penny is blurgz. [That's how we override Inform's
> default assumptions about plurals. It is documented at Kinds > Plural
> assertions.]
And as noted in my response to Adam, this won't work, because it will
produce, in the room description, "On the table you see two blurgz."
--JA
That's a one-line fix:
Understand "coins", "cents", "pennies", and "pence" as the plural of
pennies.
Because we are, in fact, understanding pennies (plurally) any time the
penny-collective is not around.
> > For what it's worth, though I don't use this method here, you can
> > override the creation of the plural to make it a different plural
> > (viz, one the player is less likely to type). E.g.:
> >
> > The plural of penny is blurgz. [That's how we override Inform's
> > default assumptions about plurals. It is documented at Kinds > Plural
> > assertions.]
>
> And as noted in my response to Adam, this won't work, because it will
> produce, in the room description, "On the table you see two blurgz."
Which is why I immediately followed those sentences with
>Then to clean up the output:
>Rule for printing the plural name of a penny:
> say "pennies".
>This is explained in the activities chapter.
As I also mentioned, you don't need to do this at present. But it is
possible.
Right off the bat, I see this line of code:
Response of Bob when given-or-shown a random penny:
say "'The payoff is three cents, bud. Don't get me mad.'"
Remove the word "random". Else, you'll sometimes (randomly) get the
say phrase and sometimes get "Bob doesn't respond."
"A penny" is synonymous with "any penny" when Penny is a class of
objects.
-Ron
I played with this some more. I'll show you what I got because I
think it'll be a useful intermediate step between your code sample and
Emily's longer (and more correct) one.
First of all, Eric's conversation extensions don't seem to agree well
with multiple object verbs. I got around this by never feeding them
any: I deleted the plural of penny. But this causes problems with
standard take & drop actions and who knows what else.
Secondly, I used the standard method of changing parser error
messages.
Third, I didn't use a collective object at all. Using a collective
object means re-writing take & drop & god knows what else in the
Standard Library to function correctly again. In such a case of
extensive re-writing, I'd rather just correct the new stuff -- Eric's
work and any Actions that now need to accept multiple stuff (via
Understand [things]) -- and do the whole thing "the right way" cause
its easier in the long run.
I didn't completely show how to do things the right way, because I
think Emily already got that.
I hope this is helpful, but if it isn't, it's at least brief.
------code sample-----------
Include Conversation Framework by Eric Eve.
Include Conversation Responses by Eric Eve.
Include Conversational Defaults by Eric Eve.
Include Plurality by Emily Short.
The Test Lab is a room. "Various tests are carried out here."
A penny is a kind of thing. The description is "A shiny copper
penny."
Understand "shiny", "copper", "coin", and "cent" as a penny.
Understand "coins", "cents", "pence", and "pennies" as a penny.
The plural of penny is penny. [destroys the plural, essentially]
Rule for printing a parser error when the parser error is can't use
multiple objects:
say "In general, you can't use multiple objects with that verb."
The table is a supporter in the Test Lab. Two pennies are on the
table.
The player carries one penny.
Bob is a man in the Test Lab.
Response of Bob when given-or-shown pennies and when the player
carries three pennies:
say "'Thanks for the payoff,' Bob says. 'Now I won't have to kill
you.'";
repeat with X running through every penny carried by the player
begin;
remove X from play;
end repeat;
Response of Bob when given-or-shown pennies and when the player
carries exactly two pennies:
say "'You're comin['] up short,' Bob complains. 'I need three
cents.'";
Response of Bob when given-or-shown one penny and when the player
carries less than two pennies:
say "'The payoff is three cents, bud. Don't get me mad.'"
test me with "give pennies to bob / take penny / give pennies to bob /
give coins to bob / drop pennies / drop all pennies / take pennies /
take all pennies / give pennies to bob / give coins to bob / drop
coins"
--------end code----------
---------transcript-------
>test me
(Testing.)
>[1] give pennies to bob
(the penny to Bob)
"The payoff is three cents, bud. Don't get me mad."
>[2] take penny
Taken.
>[3] give pennies to bob
"You're comin' up short," Bob complains. "I need three cents."
>[4] give coins to bob
"You're comin' up short," Bob complains. "I need three cents."
>[5] drop pennies
Dropped.
>[6] drop all pennies
(the penny)
Dropped.
>[7] take pennies
Taken.
>[8] take all pennies
penny: Taken.
penny: Taken.
>[9] give pennies to bob
"Thanks for the payoff," Bob says. "Now I won't have to kill you."
>[10] give coins to bob
You can't see any such thing.
>[11] drop coins
You can't see any such thing.
---------end transcript------------
Oh, you can. At least you can control what plurals the system decides;
it's just that you have to pre-empt the automated decision by declaring
the plural before you declare the kind. This is (I believe) one of the
few areas where the order of the statements in the source is important.
You say:
The plural of ox is oxen.
An ox is a kind of animal.
(This is the example given in the documentation, so if you search for
"oxen" you should be able to confirm that I've remembered it correctly -
assuming that I have!)
--jz
Not true. You can absolutely declare the plural after declaring the
kind. This compiles:
The Pen is a room. An ox is a kind of animal. The plural of ox is
oxen. Two oxen are in the Pen.
...and provides this transcript:
Pen
You can see two oxen here.
>GET OXEN
ox: I don't suppose the ox would care for that.
ox: I don't suppose the ox would care for that.
> > I don't mind writing my own code to undo the system's default behavior.
> > That's expected. But I do insist that the hooks with which to override
> > ANY default behavior be (a) provided and (b) documented.
This is documented in section 4.3, "Plural Assertions."