! ==============================================================================
! PARSER: Front end to parser.
!
-! Supplied for use with Inform 6 -- Release 6.12.3 -- Serial number 190320
+! Supplied for use with Inform 6 -- Release 6.12.6 -- Serial number 220219
!
-! Copyright Graham Nelson 1993-2004 and David Griffith 2012-2019
+! Copyright Graham Nelson 1993-2004 and David Griffith 2012-2022
!
! This file is free software: you can redistribute it and/or modify
! it under the terms of the GNU Affero General Public License as
! ------------------------------------------------------------------------------
#Ifndef VN_1633;
-Message fatalerror "*** Library 6.12.3 needs Inform v6.33 or later to work ***";
+Message fatalerror "*** Library 6.12.x needs Inform v6.33 or later to work ***";
#Endif; ! VN_
-Constant LibSerial "190320";
-Constant LibRelease "6.12.3pre";
-Constant LIBRARY_VERSION 612;
-Constant Grammar__Version 2;
+Include "version";
Constant BEFORE_PARSER 10;
Constant AFTER_PARSER 20;
Constant HDR_SCREENWCHARS $21; ! byte
Constant HDR_SCREENWUNITS $22; ! word
Constant HDR_SCREENHUNITS $24; ! word
+#Iftrue (#version_number == 6);
+Constant HDR_FONTHUNITS $26; ! byte
+Constant HDR_FONTWUNITS $27; ! byte
+#Ifnot;
Constant HDR_FONTWUNITS $26; ! byte
Constant HDR_FONTHUNITS $27; ! byte
+#Endif;
Constant HDR_ROUTINEOFFSET $28; ! word
Constant HDR_STRINGOFFSET $2A; ! word
Constant HDR_BGCOLOUR $2C; ! byte
Fake_Action PluralFound;
Fake_Action ListMiscellany;
Fake_Action Miscellany;
+Fake_Action RunTimeError;
Fake_Action Prompt;
Fake_Action NotUnderstood;
Fake_Action Going;
! "invent" routines of objects are called
Global inventory_style; ! List-writer style currently used while
! printing inventories
+
+Global objects_style; ! List-writer style currently used while
+Global places_style; ! printing objects handled or places visited
+
! ------------------------------------------------------------------------------
! Menus and printing
! ------------------------------------------------------------------------------
Constant CLR_PURPLE 7;
Constant CLR_AZURE 8;
+#Ifdef TARGET_GLULX;
+Array GlulxColourValues
+ --> (-2)
+ (-1)
+ $000000
+ $EF0000
+ $00D600
+ $EFEF00
+ $006BB5
+ $FF00FF
+ $00EFEF
+ $FFFFFF;
+#Endif; ! TARGET_GLULX
+
Constant WIN_ALL 0;
Constant WIN_STATUS 1;
Constant WIN_MAIN 2;
! If you want to use the third-person of the narrative voice, you will
! need to replace this selfobj with your own.
-
Class SelfClass
with name ',a' ',b' ',c' ',d' ',e',
short_name YOURSELF__TX,
each_turn NULL,
time_out NULL,
describe NULL,
- article "the",
+ article THE__TX,
add_to_scope 0,
capacity 100,
parse_name 0,
w2 = a_table-->(3*oops_from - 1); ! Length of word to go
#Endif; ! TARGET_
-#IfDef OOPS_CHECK;
+#Ifdef OOPS_CHECK;
print "[~";
for (i=0 : i<w2 : i++) for (i=0 : i<w2 : i++) print (char)a_buffer->(i+w);
print "~ --> ~";
for (i=0 : i<x2 : i++) {
a_buffer->(i+w) = buffer2->(i+x1);
-#IfDef OOPS_CHECK;
+#Ifdef OOPS_CHECK;
print (char) buffer2->(i+x1);
#Endif;
}
-#IfDef OOPS_CHECK;
+#Ifdef OOPS_CHECK;
print "~]^^";
#Endif;
i = (~~i);
#Endif; ! TARGET_
if (i == 0) { L__M(##Miscellany, 7); return 0; }
- L__M(##Miscellany, 1);
+ L__M(##Miscellany, 6);
return 1;
];
if (usual_grammar_after == 0) {
j = verb_wordnum;
+ #Ifdef TARGET_ZCODE;
+ parser_one = 0;
+ #Endif;
i = RunRoutines(actor, grammar);
#Ifdef DEBUG;
if (parser_trace >= 2 && actor.grammar ~= 0 or NULL)
#Ifdef TARGET_ZCODE;
if ((i ~= 0 or 1) &&
+ (parser_one ~= 0 ||
(UnsignedCompare(i, dict_start) < 0 ||
UnsignedCompare(i, dict_end) >= 0 ||
- (i - dict_start) % dict_entry_size ~= 0)) {
+ (i - dict_start) % dict_entry_size ~= 0))) {
usual_grammar_after = j;
i=-i;
}
if (verb_word == 0 || ((verb_word->#dict_par1) & DICT_VERB) == 0) {
- ! So is the first word an object contained in the special object "compass"
+ ! So is the first word an object contained in the special object "Compass"
! (i.e., a direction)? This needs use of NounDomain, a routine which
! does the object matching, returning the object number, or 0 if none found,
! or REPARSE_CODE if it has restructured the parse table so the whole parse
! must be begun again...
wn = verb_wordnum; indef_mode = false; token_filter = 0;
- l = NounDomain(compass, 0, NOUN_TOKEN);
+ l = NounDomain(Compass, 0, NOUN_TOKEN);
if (l == REPARSE_CODE) jump ReParse;
! If it is a direction, send back the results:
oops_from = 0;
! ...explain any inferences made (using the pattern)...
-
+ ! This is where the parser replies (the sword) if things aren't clear.
if (inferfrom ~= 0 && no_infer_message == false) {
print "("; PrintCommand(inferfrom); print ")^";
}
indef_nspec_at = 0;
];
-[ Descriptors allows_multiple o x flag cto type m n;
+[ Descriptors allows_multiple o x y flag cto type m n;
ResetDescriptors();
if (wn > num_words) return 0;
m = wn;
for (flag=true : flag :) {
o = NextWordStopped(); flag = false;
- for (x=1 : x<=LanguageDescriptors-->0 : x=x+4)
+ for (x=1 : x<=LanguageDescriptors-->0 : x=x+4) {
if (o == LanguageDescriptors-->x) {
+ ! Attempt to compensate for her-her confusion.
+ for (y = 1 : y<=LanguagePronouns-->0 : y=y+2) {
+ if (o == LanguagePronouns-->y)
+ jump PersonalPronoun;
+ }
flag = true;
type = LanguageDescriptors-->(x+2);
if (type ~= DEFART_PK) indef_mode = true;
if (type == light) indef_type = indef_type | LIT_BIT;
if (type == -light) indef_type = indef_type | UNLIT_BIT;
}
+ }
+ .PersonalPronoun;
+
if (o == OTHER1__WD or OTHER2__WD or OTHER3__WD) {
indef_mode = 1; flag = 1;
indef_type = indef_type | OTHER_BIT;
if (actor ~= player) rtrue;
if (obj has animate) rtrue;
if (obj hasnt talkable) rfalse;
- if (action_to_be == ##Ask or ##Answer or ##Tell or ##AskFor) rtrue;
+ if (action_to_be == ##Ask or ##Answer or ##Tell or ##AskFor or ##AskTo) rtrue;
rfalse;
];
parsed_number = l; return GPR_NUMBER;
CREATURE_TOKEN:
- if (action_to_be == ##Answer or ##Ask or ##AskFor or ##Tell)
+ if (action_to_be == ##Answer or ##Ask or ##AskFor or ##AskTo or ##Tell)
scope_reason = TALKING_REASON;
TOPIC_TOKEN:
#Endif; ! DEBUG
l = NounDomain(actors_location, actor, token);
if (l == REPARSE_CODE) return l; ! Reparse after Q&A
- if (l ~= nothing && l ~= 1 && l notin actor && token == MULTIHELD_TOKEN or MULTIEXCEPT_TOKEN) {
- if (ImplicitTake(l)) {
- etype = NOTHELD_PE;
- jump FailToken;
- }
- }
if (indef_wanted == 100 && l == 0 && number_matched == 0)
l = 1; ! ReviseMulti if TAKE ALL FROM empty container
wn = desc_wn;
jump TryAgain2;
}
- if (etype ~=TOOFEW_PE && (multiflag || etype ~= MULTI_PE))
+ if ((etype ~=TOOFEW_PE && etype ~= VAGUE_PE) && (multiflag || etype ~= MULTI_PE))
etype = CantSee();
jump FailToken;
} ! Choose best error
number_of_classes = 0;
- if (match_length == 0 && indef_mode && indef_wanted ~= 100)
+ if (match_length == 0 && indef_mode && indef_wanted > 0 && indef_wanted < 100)
number_matched = 0; ! ask question for 'take three'
if (number_matched == 1) i = match_list-->0;
if (number_matched > 1) {
}
if (flag) {
+ if(match_length == 1) {
+ k = 0;
+ for (i=1 : i<=number_of_classes : i++) {
+ while ((match_classes-->k) ~= i or -i) k++;
+ j = match_list-->k;
+
+ if(MatchWord(j, match_from)) {
+ no_infer_message = true;
+ return j;
+ }
+ }
+ }
#Ifdef DEBUG;
if (parser_trace >= 4) print " Unable to choose best group, so ask player.]^";
#Endif; ! DEBUG
if (its_owner == actors_location) its_score = its_score + l_s;
else {
#Ifdef TRADITIONAL_TAKE_ALL;
- if (its_owner ~= compass) its_score = its_score + SCORE__NOTCOMPASS;
+ if (its_owner ~= Compass) its_score = its_score + SCORE__NOTCOMPASS;
#Ifnot;
- if (its_owner ~= compass)
+ if (its_owner ~= Compass)
if (take_all_rule && its_owner &&
its_owner has static or scenery &&
(its_owner has supporter ||
[ Identical o1 o2 p1 p2 n1 n2 i j flag;
if (o1 == o2) rtrue; ! This should never happen, but to be on the safe side
if (o1 == 0 || o2 == 0) rfalse; ! Similarly
- if (parent(o1) == compass || parent(o2) == compass) rfalse; ! Saves time
+ if (parent(o1) == Compass || parent(o2) == Compass) rfalse; ! Saves time
! What complicates things is that o1 or o2 might have a parsing routine,
! so the parser can't know from here whether they are or aren't the same.
rtrue;
];
+
+! ----------------------------------------------------------------------------
+! MatchWord matches a word to the name of an object. This is used to assume
+! that an object simply named "key" is meant when the player types TAKE KEY
+! rather than TAKE BRASS KEY.
+! ----------------------------------------------------------------------------
+
+[ MatchWord p_obj p_word_no len_name len_input start_input i;
+
+ p_word_no--;
+
+ PrintToBuffer(StorageForShortName, SHORTNAMEBUF_LEN, p_obj);
+ len_name = StorageForShortName --> 0;
+
+ if(len_name > 9) {
+ for(i = 9 : i < len_name : i++)
+ if(StorageForShortName -> (WORDSIZE + i) == 32) rfalse;
+ len_name = 9;
+ }
+
+#Ifdef TARGET_ZCODE;
+ start_input = (parse + 2) -> (4 * p_word_no + 3);
+ len_input = (parse + 2) -> (4 * p_word_no + 2);
+ if(len_input > 9) len_input = 9;
+ if(len_name ~= len_input) rfalse;
+ for(i = 0 : i < len_name : i++) {
+ if(StorageForShortName -> (WORDSIZE + i) ~= buffer -> (start_input + i))
+ rfalse;
+ }
+#Ifnot; ! TARGET_GLULX
+ start_input = parse --> (((p_word_no+1) * 3)) - 2;
+ len_input = parse --> ((p_word_no+1) * 3 - 1);
+ if(len_input > 9) len_input = 9;
+ if(len_name ~= len_input) rfalse;
+ for(i = 0 : i < len_name : i++) {
+ if(StorageForShortName -> (WORDSIZE + i) ~= buffer -> (start_input + i + 2))
+ rfalse;
+ }
+#Endif; ! TARGET_
+
+ rtrue;
+];
+
+
! ----------------------------------------------------------------------------
! PrintCommand reconstructs the command as it presently reads, from
! the pattern which has been built up
if (i >= REPARSE_CODE)
print (address) No__Dword(i-REPARSE_CODE);
else
- if (i in compass && LanguageVerbLikesAdverb(verb_word))
+ if (i in Compass && LanguageVerbLikesAdverb(verb_word))
LanguageDirection (i.door_dir); ! the direction name as adverb
else
print (the) i;
if (indef_mode==0 && domain==actors_location
&& scope_reason==PARSING_REASON && context~=CREATURE_TOKEN)
- ScopeWithin(compass);
+ ScopeWithin(Compass);
! Look through the objects in the domain, avoiding "objectloop" in case
! movements occur, e.g. when trying each_turn.
#Ifdef DEBUG;
if (threshold >= 0 && parser_trace >= 5) print " ParseNoun returned ", threshold, "^";
#Endif; ! DEBUG
- if (threshold < 0) wn++;
- if (threshold > 0) { k = threshold; jump MMbyPN; }
-
- if (threshold == 0 || Refers(obj,wn-1) == 0) {
- .NoWordsMatch;
- if (indef_mode ~= 0) {
- k = 0; parser_action = NULL;
- jump MMbyPN;
- }
- rfalse;
+ ! Don't arbitrarily increase wn when ParseNoun() returns -1
+ if (threshold > 0) {
+ k = threshold;
+ wn = j + k;
+ jump MMbyPN;
+ }
+ ! Check wn instead of wn - 1
+ if (threshold == 0 || Refers(obj,wn) == 0) {
+ .NoWordsMatch;
+ if (indef_mode ~= 0) {
+ ! Restore wn to pre-ParseNoun() state
+ k = 0; parser_action = NULL; wn = j;
+ jump MMbyPN;
+ }
+ rfalse;
}
if (threshold < 0) {
- threshold = 1;
- dict_flags_of_noun = (w->#dict_par1) & (DICT_X654+DICT_PLUR);!$$01110100;
- w = NextWord();
+ ! Set threshold to reflect any words consumed by ParseNoun()
+ threshold = wn - j;
+ w = NextWord(); ! Ensure w contains actual first word of noun phrase
+ ! if ParseNoun() moved wn.
+ dict_flags_of_noun = (w->#dict_par1) & (DICT_X654+DICT_PLUR);!$$01110100;
while (Refers(obj, wn-1)) {
threshold++;
if (w)
default: return GPR_FAIL;
}
if (digit >= base) return GPR_FAIL;
- digit_count++;
switch (base) {
16: if (digit_count > 2*WORDSIZE) return GPR_FAIL;
2: if (digit_count > 8*WORDSIZE) return GPR_FAIL;
#Ifdef TARGET_ZCODE;
-[ Dword__No w; return (w-(HDR_DICTIONARY-->0 + 7))/9; ];
-[ No__Dword n; return HDR_DICTIONARY-->0 + 7 + 9*n; ];
+[ Dword__No w dp dh;
+ dp = HDR_DICTIONARY-->0;
+ dh = dp->0 + 4;
+ dp = dp + dp->0 + 1;
+ return (w-(HDR_DICTIONARY-->0 + dh )) / (dp->0);
+];
+
+[ No__Dword n dp dh;
+ dp = HDR_DICTIONARY-->0;
+ dh = dp->0 + 4;
+ dp = dp + dp->0 + 1;
+ return HDR_DICTIONARY-->0 + dh + (dp->0 *n);
+];
#Ifnot; ! TARGET_GLULX
}
l = multiple_object-->k;
PronounNotice(l);
- print (name) l, (string) COLON__TX;
+ print (name) l, (string) COLON__TX, " ";
if (inp1 == 0) {
inp1 = l;
switch (self.actor_act(actor, action, l, second)) {
if (lightflag == 0) location = thedark;
if (j ~= 2) Banner();
-#ifndef NOINITIAL_LOOK;
+#Ifndef NOINITIAL_LOOK;
<Look>;
-#endif;
+#Endif;
before_first_turn = false;
];
[ GameEpilogue;
+ if (score ~= last_score) {
+ if (notify_mode == 1) NotifyTheScore();
+ last_score = score;
+ }
print "^^ ";
#Ifdef TARGET_ZCODE;
#IfV5; style bold; #Endif; ! V5
];
#Ifdef COLOUR;
-[ SetColour f b window doclear i fwd bwd swin;
- if (window) swin = 5-window; ! 4 for TextGrid, 3 for TextBuffer
-
- if (clr_on) {
- fwd = MakeColourWord(f);
- bwd = MakeColourWord(b);
- for (i=0 : i<=10: i++) {
- if (f == CLR_DEFAULT || b == CLR_DEFAULT) { ! remove style hints
- glk_stylehint_clear(swin, i, 7);
- glk_stylehint_clear(swin, i, 8);
- }
- else {
- glk_stylehint_set(swin, i, 7, fwd);
- glk_stylehint_set(swin, i, 8, bwd);
- }
- }
- ! Now re-open the windows to apply the hints
- if (gg_statuswin) glk_window_close(gg_statuswin, 0);
-
- if (doclear || ( window ~= 1 && (clr_fg ~= f || clr_bg ~= b) ) ) {
- glk_window_close(gg_mainwin, 0);
- gg_mainwin = glk_window_open(0, 0, 0, 3, GG_MAINWIN_ROCK);
- if (gg_scriptstr ~= 0)
- glk_window_set_echo_stream(gg_mainwin, gg_scriptstr);
- }
-
- gg_statuswin = glk_window_open($12, gg_statuswin_cursize,
- 4, GG_STATUSWIN_ROCK);
- if (statuswin_current && gg_statuswin)
- MoveCursor(); else MainWindow();
+[ SetColour f b window;
+ if (window == 0) { ! if setting both together, set reverse
+ clr_fgstatus = b;
+ clr_bgstatus = f;
}
-
- if (window ~= 2) {
+ if (window == 1) {
clr_fgstatus = f;
clr_bgstatus = b;
}
- if (window ~= 1) {
+ if (window == 0 or 2) {
clr_fg = f;
clr_bg = b;
}
+ if (clr_on) {
+ if (glk_gestalt(gestalt_GarglkText, 0)) {
+ if (f >= 0 && f < 10) {
+ f = GlulxColourValues-->f;
+ }
+ else {
+ f = -2;
+ }
+ if (b >= 0 && b < 10) {
+ b = GlulxColourValues-->b;
+ }
+ else {
+ b = -2;
+ }
+ garglk_set_zcolors(f, b);
+ }
+ }
];
#Endif; ! COLOUR
#Endif; ! TARGET_
#Endif; ! TARGET_ZCODE
#Ifndef DrawStatusLine;
-[ DrawStatusLine width posa posb posc;
+[ DrawStatusLine width posa posb posc posd pose;
#Ifdef TARGET_GLULX;
! If we have no status window, we must not try to redraw it.
if (gg_statuswin == 0)
MoveCursor(1, 1);
width = ScreenWidth();
- posa = width-26;
+ posa = width-26; ! For standard move/score display.
posb = width-13;
posc = width-5;
+
+ posd = width-19; ! For time display.
+ pose = width-14;
+
spaces width;
MoveCursor(1, 2);
else
print (The) visibility_ceiling;
}
-
- if (sys_statusline_flag && width > 53) {
- MoveCursor(1, posa);
- print (string) TIME__TX;
- LanguageTimeOfDay(sline1, sline2);
- }
- else {
+ if (sys_statusline_flag) {
+ if (width > 29) {
+ if (width > 39)
+ MoveCursor(1, posd);
+ else
+ MoveCursor(1, pose);
+ print (string) TIME__TX;
+ LanguageTimeOfDay(sline1, sline2);
+ } else
+ jump DSLContinue;
+ } else {
if (width > 66) {
#Ifndef NO_SCORE;
MoveCursor(1, posa);
#Endif;
}
}
-
+ .DSLContinue;
MainWindow(); ! set_window
];
#Endif;
PrintCapitalised(a, b, false, true, true);
];
-[ CapitRule str no_caps;
+[ Cap str no_caps;
if (no_caps) print (string) str;
else PrintCapitalised(str,0,true);
];
if (o provides articles) {
artval=(o.&articles)-->(acode+short_name_case*LanguageCases);
if (capitalise)
- print (CapitRule) artval;
+ print (Cap) artval;
else
print (string) artval;
if (pluralise) return;
}
#Endif; ! TARGET_
- CapitRule (artform-->acode, ~~capitalise); ! print article
+ Cap (artform-->acode, ~~capitalise); ! print article
if (pluralise) return;
print (PSN__) o;
];
ext_printverb 0, ! [C2/R2]
ext_timepasses 0, ! [C2/R1]
ext_unknownverb 0, ! [C2/R2]
+ ext_aftersave 0, ! [C2/R2]
+ ext_afterrestore 0, ! [C2/R2]
! [C1] = Called in all cases
! [C2] = Called if EP is undefined, or returns false
! [C3] = called if EP is undefined, or returns -1