! Positions.h
! Version 1.1
! An Inform 6 extension by Nathan Schwartzman
! Feedback to naschwar@iupui.edu
!
! #Include between "Parser" and "Verblib".
! Before #Including "Parser", add the line
! "Replace TrygivenObject".
!
! This extension will allow input of the following type:
!
! TAKE THE BRASS KEY FROM THE POUCH IN THE TREASURE CHEST
!
! PUT EVERYTHING IN THE TOASTER ON THE TABLE
!
! This does not require you to alter existing
! code at all, unless you already have a replacement
! for TryGivenObject() for some reason.
!
! What doesn't work:
! PUT ALL IN CHEST ON CHAIR (may work by fiddling with
!  grammar lines)
! Pronouns (e.g. X IT IN CHEST)
!
! Credit goes to Anson Turner and his Platypus library
! for the idea for this; I also took some of his code.
! I hope he doesn't mind.
!
! Version 1.1 fixes a bug and allows the use of articles
! and descriptors.

Global indef_specific;

[ TryGivenObject obj flag threshold k w j p;

    #Ifdef DEBUG;
    if (parser_trace >= 5) print "    Trying ", (the) obj, " (", obj, ") at word ", wn, "^";
    #Endif; ! DEBUG

    dict_flags_of_noun = 0;

!  If input has run out then always match, with only quality 0 (this saves
!  time).

    if (wn > num_words) {
        if (indef_mode ~= 0)
            dict_flags_of_noun = $$01110000;  ! Reject "plural" bit
        MakeMatch(obj,0);
        #Ifdef DEBUG;
        if (parser_trace >= 5) print "    Matched (0)^";
        #Endif; ! DEBUG
        return 1;
    }

!  Ask the object to parse itself if necessary, sitting up and taking notice
!  if it says the plural was used:

    if (obj.parse_name~=0) {
        parser_action = NULL; j=wn;
        k = RunRoutines(obj,parse_name);
        if (k > 0) {
            wn=j+k;

          .MMbyPN;

		! The next two lines take care of position parsing.

		p = AppendPreps(obj);
		if (p) { wn = wn + p; k = k + p; }

            if (parser_action == ##PluralFound)
                dict_flags_of_noun = dict_flags_of_noun | 4;

            if (dict_flags_of_noun & 4) {
                if (~~allow_plurals) k = 0;
                else {
                    if (indef_mode == 0) {
                        indef_mode = 1; indef_type = 0; indef_wanted = 0;
                    }
                    indef_type = indef_type | PLURAL_BIT;
                    if (indef_wanted == 0) indef_wanted = 100;
                }
            }

            #Ifdef DEBUG;
            if (parser_trace >= 5) print "    Matched (", k, ")^";
            #Endif; ! DEBUG
            if (~~flag) MakeMatch(obj,k);
            return k;
        }
        if (k == 0) jump NoWordsMatch;
    }

    ! The default algorithm is simply to count up how many words pass the
    ! Refers test:

    parser_action = NULL;

    w = NounWord();

    if (w == 1 && player == obj) { k=1; jump MMbyPN; }

    if (w >= 2 && w < 128 && (LanguagePronouns-->w == obj)) { k = 1; jump MMbyPN; }

    j=--wn;
    threshold = ParseNoun(obj);
    #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;
    }

    if (threshold < 0) {
        threshold = 1;
        dict_flags_of_noun = (w->#dict_par1) & $$01110100;
        w = NextWord();
        while (Refers(obj, wn-1)) {
            threshold++;
            if (w)
               dict_flags_of_noun = dict_flags_of_noun | ((w->#dict_par1) & $$01110100);
            w = NextWord();
        }
    }

    k = threshold;
    jump MMbyPN;
];

[ AppendPreps obj wd i m ap z x;

	! Here we handle the case of PUT THE DAGGER IN THE SHEATH ON MY BELT.

	if (~~parent(obj)) rfalse;

	wn--; wd = NextWord();

        if ((parent(obj) has container && wd == 'in' or 'inside' or 'within' or 'from')
		|| (parent(obj) has supporter && wd == 'on' or 'upon' or 'off' or 'from')) {

            ! Are we sure we have PUT (DAGGER) IN (SHEATH) rather than PUT (DAGGER IN SHEATH)?

		for (x=1 : x<=LanguageDescriptors-->0 : x=x+4)
            	if (NextWord() == LanguageDescriptors-->x) {
				m++;
			}
			else wn--;

            if (line_ttype-->pcount == PREPOSITION_TT)
            {   z = pcount;
                if (WordLeft(line_tdata-->z)) jump Prepositions2;
                if ((line_token-->z)->0 & $20)
                {   do
                    {   if (WordLeft(line_tdata-->z)) jump Prepositions2;
                        z++;
                    } until ((line_token-->z == ENDIT_TOKEN)
                              || (((line_token-->z)->0 & $10) == 0));
                }
                jump GiveResult;
            }

		! Ok, now we're sure.

            .Prepositions2;

		ap = allow_plurals;
		i = TryGivenObject(parent(obj), 1);
		allow_plurals = ap;
		if (~~i) jump GiveResult;

		m = m + i + 1;
		obj = parent(obj);
	  }

	.GiveResult;

	if (i == 0) rfalse;
	if (indef_wanted == 100) {
		if (parent(obj) has container) indef_specific = 1;
		if (parent(obj) has supporter) indef_specific = 2;
	}
	return m;
];

[ WordLeft w     own cw flag;
    own = wn;
    while ((cw = NextWordStopped()) ~= -1)
    {   if (flag)
        {   if (cw && (cw->#dict_par1) & 1) break;
            flag = 0;
        }
        if (cw == w) { wn = own; rtrue; }
        if (IsALinkWord(w)) flag = 1;
    }
    wn = own;
    rfalse;
];

[ IsALinkWord wd;
    if (wd == COMMA_WORD or AND1__WD or AND2__WD or AND3__WD
        or THEN1__WD or THEN2__WD or THEN3__WD)
        rtrue;
    rfalse;
];