If you just wanted to stop commands like “take the apple and the beer and the backpack”, “take all” and give the message “You can’t use multiple objects with that verb.” instead, then this should work.
[spoiler][code]“Test”
Include (-
! This is an actual specified object, and is therefore where a typing error
! is most likely to occur, so we set:
oops_from = wn;
! So, two cases. Case 1: token not equal to "held" (so, no implicit takes)
! but we may well be dealing with multiple objects
! In either case below we use NounDomain, giving it the token number as
! context, and two places to look: among the actor's possessions, and in the
! present location. (Note that the order depends on which is likeliest.)
if (token ~= HELD_TOKEN) {
i = multiple_object-->0;
#Ifdef DEBUG;
if (parser_trace >= 3) print " [Calling NounDomain on location and actor]^";
#Endif; ! DEBUG
l = NounDomain(actors_location, actor, token);
if (l == REPARSE_CODE) return l; ! Reparse after Q&A
if (indef_wanted == INDEF_ALL_WANTED && l == 0 && number_matched == 0)
l = 1; ! ReviseMulti if TAKE ALL FROM empty container
if (token_allows_multiple && ~~multiflag) {
if (best_etype==MULTI_PE) best_etype=STUCK_PE;
multiflag = true;
}
if (l == 0) {
if (indef_possambig) {
ResetDescriptors();
wn = desc_wn;
jump TryAgain2;
}
!if (etype == MULTI_PE or TOOFEW_PE && multiflag) etype = STUCK_PE;
etype=CantSee();
jump FailToken;
} ! Choose best error
#Ifdef DEBUG;
if (parser_trace >= 3) {
if (l > 1) print " [ND returned ", (the) l, "]^";
else {
print " [ND appended to the multiple object list:^";
k = multiple_object-->0;
for (j=i+1 : j<=k : j++)
print " Entry ", j, ": ", (The) multiple_object-->j,
" (", multiple_object-->j, ")^";
print " List now has size ", k, "]^";
}
}
#Endif; ! DEBUG
if (l == 1) {
if (~~many_flag) many_flag = true;
else { ! Merge with earlier ones
k = multiple_object-->0; ! (with either parity)
multiple_object-->0 = i;
for (j=i+1 : j<=k : j++) {
if (and_parity) MultiAdd(multiple_object-->j);
else MultiSub(multiple_object-->j);
}
#Ifdef DEBUG;
if (parser_trace >= 3)
print " [Merging ", k-i, " new objects to the ", i, " old ones]^";
#Endif; ! DEBUG
}
}
else {
! A single object was indeed found
if (match_length == 0 && indef_possambig) {
! So the answer had to be inferred from no textual data,
! and we know that there was an ambiguity in the descriptor
! stage (such as a word which could be a pronoun being
! parsed as an article or possessive). It's worth having
! another go.
ResetDescriptors();
wn = desc_wn;
jump TryAgain2;
}
if ((token == CREATURE_TOKEN) && (CreatureTest(l) == 0)) {
etype = ANIMA_PE;
jump FailToken;
} ! Animation is required
if (~~many_flag) single_object = l;
else {
if (and_parity) MultiAdd(l); else MultiSub(l);
#Ifdef DEBUG;
if (parser_trace >= 3) print " [Combining ", (the) l, " with list]^";
#Endif; ! DEBUG
}
}
}
else {
! Case 2: token is "held" (which fortunately can't take multiple objects)
! and may generate an implicit take
l = NounDomain(actor,actors_location,token); ! Same as above...
if (l == REPARSE_CODE) return l;
if (l == 0) {
if (indef_possambig) {
ResetDescriptors();
wn = desc_wn;
jump TryAgain2;
}
etype = CantSee(); jump FailToken; ! Choose best error
}
! ...until it produces something not held by the actor. Then an implicit
! take must be tried. If this is already happening anyway, things are too
! confused and we have to give up (but saving the oops marker so as to get
! it on the right word afterwards).
! The point of this last rule is that a sequence like
!
! > read newspaper
! (taking the newspaper first)
! The dwarf unexpectedly prevents you from taking the newspaper!
!
! should not be allowed to go into an infinite repeat - read becomes
! take then read, but take has no effect, so read becomes take then read...
! Anyway for now all we do is record the number of the object to take.
o = parent(l);
if (o ~= actor) {
#Ifdef DEBUG;
if (parser_trace >= 3) print " [Allowing object ", (the) l, " for now]^";
#Endif; ! DEBUG
}
single_object = l;
} ! end of if (token ~= HELD_TOKEN) else
! The following moves the word marker to just past the named object...
wn = oops_from + match_length;
-) instead of “Parse Token Letter D” in “Parser.i6t”.
Include (-
! Object(s) specified now: is that the end of the list, or have we reached
! "and", "but" and so on? If so, create a multiple-object list if we
! haven't already (and are allowed to).
.NextInList;
o = NextWord();
if (o == AND1__WD or AND2__WD or AND3__WD or BUT1__WD or BUT2__WD or BUT3__WD or comma_word) {
#Ifdef DEBUG;
if (parser_trace >= 3) print " [Read connective '", (address) o, "']^";
#Endif; ! DEBUG
!if (~~token_allows_multiple) {
!if (multiflag) jump PassToken; ! give UPTO_PE error
etype=MULTI_PE;
jump FailToken;
!}
if (o == BUT1__WD or BUT2__WD or BUT3__WD) and_parity = 1-and_parity;
if (~~many_flag) {
multiple_object-->0 = 1;
multiple_object-->1 = single_object;
many_flag = true;
#Ifdef DEBUG;
if (parser_trace >= 3) print " [Making new list from ", (the) single_object, "]^";
#Endif; ! DEBUG
}
dont_infer = true; inferfrom=0; ! Don't print (inferences)
jump ObjectList; ! And back around
}
wn--; ! Word marker back to first not-understood word
-) instead of “Parse Token Letter E” in “Parser.i6t”.
Include (-
[ Adjudicate context i j k good_ones last n ultimate flag offset;
#Ifdef DEBUG;
if (parser_trace >= 4) {
print " [Adjudicating match list of size ", number_matched,
" in context ", context, “^”;
print " ";
if (indef_mode) {
print "indefinite type: ";
if (indef_type & OTHER_BIT) print "other ";
if (indef_type & MY_BIT) print "my ";
if (indef_type & THAT_BIT) print "that ";
if (indef_type & PLURAL_BIT) print "plural ";
if (indef_type & LIT_BIT) print "lit ";
if (indef_type & UNLIT_BIT) print "unlit ";
if (indef_owner ~= 0) print “owner:”, (name) indef_owner;
new_line;
print " number wanted: ";
if (indef_wanted == INDEF_ALL_WANTED) print “all”; else print indef_wanted;
new_line;
print " most likely GNAs of names: ", indef_cases, “^”;
}
else print “definite object^”;
}
#Endif; ! DEBUG
j = number_matched-1; good_ones = 0; last = match_list-->0;
for (i=0 : i<=j : i++) {
n = match_list-->i;
match_scores-->i = good_ones;
ultimate = ScopeCeiling(n);
if (context==HELD_TOKEN && parent(n)==actor)
{ good_ones++; last=n; }
if (context==MULTI_TOKEN && ultimate==ScopeCeiling(actor)
&& n~=actor && n hasnt concealed && n hasnt scenery)
{ good_ones++; last=n; }
if (context==MULTIHELD_TOKEN && parent(n)==actor)
{ good_ones++; last=n; }
if (context==MULTIEXCEPT_TOKEN or MULTIINSIDE_TOKEN)
{ if (advance_warning==-1)
{ if (context==MULTIEXCEPT_TOKEN)
{ good_ones++; last=n;
}
if (context==MULTIINSIDE_TOKEN)
{ if (parent(n)~=actor) { good_ones++; last=n; }
}
}
else
{ if (context==MULTIEXCEPT_TOKEN && n~=advance_warning)
{ good_ones++; last=n; }
if (context==MULTIINSIDE_TOKEN && n in advance_warning)
{ good_ones++; last=n; }
}
}
if (context==CREATURE_TOKEN && CreatureTest(n)==1)
{ good_ones++; last=n; }
match_scores-->i = 1000*(good_ones - match_scores-->i);
}
if (good_ones == 1) return last;
! If there is ambiguity about what was typed, but it definitely wasn't
! animate as required, then return anything; higher up in the parser
! a suitable error will be given. (This prevents a question being asked.)
if (context == CREATURE_TOKEN && good_ones == 0) return match_list-->0;
if (indef_mode == 0) indef_type=0;
ScoreMatchL(context);
if (number_matched == 0) return -1;
if (indef_mode == 0) {
! Is there now a single highest-scoring object?
i = SingleBestGuess();
if (i >= 0) {
#Ifdef DEBUG;
if (parser_trace >= 4) print " Single best-scoring object returned.]^";
#Endif; ! DEBUG
return i;
}
}
if (indef_mode == 1 && indef_type & PLURAL_BIT ~= 0) {
!if (context ~= MULTI_TOKEN or MULTIHELD_TOKEN or MULTIEXCEPT_TOKEN
!or MULTIINSIDE_TOKEN) {
etype = MULTI_PE;
return -1;
!}
i = 0; offset = multiple_object-->0;
for (j=BestGuess(): j~=-1 && i<indef_wanted && i+offset<MATCH_LIST_WORDS-1:
j=BestGuess()) {
flag = 0;
BeginActivity(DECIDING_WHETHER_ALL_INC_ACT, j);
if ((ForActivity(DECIDING_WHETHER_ALL_INC_ACT, j)) == 0) {
if (j hasnt concealed && j hasnt worn) flag = 1;
if (context == MULTIHELD_TOKEN or MULTIEXCEPT_TOKEN && parent(j) ~= actor)
flag = 0;
if (action_to_be == ##Take or ##Remove && parent(j) == actor)
flag = 0;
k = ChooseObjects(j, flag);
if (k == 1)
flag = 1;
else {
if (k == 2) flag = 0;
}
} else {
flag = 0; if (RulebookSucceeded()) flag = 1;
}
EndActivity(DECIDING_WHETHER_ALL_INC_ACT, j);
if (flag == 1) {
i++; multiple_object-->(i+offset) = j;
#Ifdef DEBUG;
if (parser_trace >= 4) print " Accepting it^";
#Endif; ! DEBUG
}
else {
i = i;
#Ifdef DEBUG;
if (parser_trace >= 4) print " Rejecting it^";
#Endif; ! DEBUG
}
}
if (i < indef_wanted && indef_wanted < INDEF_ALL_WANTED) {
etype = TOOFEW_PE; multi_wanted = indef_wanted;
multi_had=i;
return -1;
}
multiple_object-->0 = i+offset;
multi_context = context;
#Ifdef DEBUG;
if (parser_trace >= 4)
print " Made multiple object of size ", i, "]^";
#Endif; ! DEBUG
return 1;
}
for (i=0 : i<number_matched : i++) match_classes-->i = 0;
n = 1;
for (i=0 : i<number_matched : i++)
if (match_classes-->i == 0) {
match_classes-->i = n++; flag = 0;
for (j=i+1 : j<number_matched : j++)
if (match_classes-->j == 0 && Identical(match_list-->i, match_list-->j) == 1) {
flag=1;
match_classes-->j = match_classes-->i;
}
if (flag == 1) match_classes-->i = 1-n;
}
n--; number_of_classes = n;
#Ifdef DEBUG;
if (parser_trace >= 4) {
print " Grouped into ", n, " possibilities by name:^";
for (i=0 : i<number_matched : i++)
if (match_classes-->i > 0)
print " ", (The) match_list-->i, " (", match_list-->i, ") --- group ",
match_classes-->i, "^";
}
#Endif; ! DEBUG
if (indef_mode == 0) {
if (n > 1) {
k = -1;
for (i=0 : i<number_matched : i++) {
if (match_scores-->i > k) {
k = match_scores-->i;
j = match_classes-->i; j = j*j;
flag = 0;
}
else
if (match_scores-->i == k) {
if ((match_classes-->i) * (match_classes-->i) ~= j)
flag = 1;
}
}
if (flag) {
#Ifdef DEBUG;
if (parser_trace >= 4) print " Unable to choose best group, so ask player.]^";
#Endif; ! DEBUG
return 0;
}
#Ifdef DEBUG;
if (parser_trace >= 4) print " Best choices are all from the same group.^";
#Endif; ! DEBUG
}
}
! When the player is really vague, or there's a single collection of
! indistinguishable objects to choose from, choose the one the player
! most recently acquired, or if the player has none of them, then
! the one most recently put where it is.
if (n == 1) dont_infer = true;
return BestGuess();
]; ! Adjudicate
-) instead of “Adjudicate” in “Parser.i6t”.
The Testing Room is A Room.
An apple, a beer and a backpack are in the testing room.
Before doing anything other than taking or dropping or looking: say “You can only take the apple!” instead.
Before taking anything when the noun is not the apple: say “You can only take the apple!” instead.
Test me with “eat apple / drink beer / take backpack / take apple / drop apple / take all / take the apple and the beer and the backpack”.[/code][/spoiler]
This will prevent taking multiple things at once.