/************************************************************************* * Possess.t: Using possessives as adjectives. * * By Garth Dighton, with help from Mike Roberts and Kevin Forchione on RAIF * This module is freely distributable and modifiable, as long as the credits * remain intact. * * This module enables players to refer to objects in the possession of actors * with possessive adjectives: "ASK JANE ABOUT HER BOX, ASK BOB ABOUT GEORGE'S * BOX", or similar. * * To use, each Actor should have the possessives property -- a list of * single-quoted words which are added to the adjectives list of objects they * carry. 'Her' and 'his' can be ignored. * Example: * Jane: Actor * noun = 'jane' * adjective = 'plain' * sdesc = "Jane" * possessives = ['jane\'s' 'girl\'s'] * ; * If any of these functions are overridden in your code, you'll have to make * adjustments: * thing.moveInto * parseNounPhrase * parseDisambig * Functions added * thing.Grab() -- Hook called when something is removed from an object's * possession. * thing.Accept() -- Hook called when somthing is moved into an object's * possession. * These functions are overridden in Actor to provides the necessary * functionality. You can still add your own code, as long as the Actor code * gets called *******************************************************************/ #ifndef POSSESS_T #define POSSESS_T #pragma C+ modify thing // Add an Accept(obj) hook to moveInto: moveInto(obj) = { local loc; /* * For the object containing me, and its container, and so forth, * tell it via a Grab message that I'm going away. */ loc = self.location; while (loc) { loc.Grab(self); loc = loc.location; } if (self.location) self.location.contents = self.location.contents - self; self.location = obj; if (obj) { obj.contents = obj.contents + self; loc = self.location; while (loc) { loc.Accept(self); loc = loc.location; } } } Grab(obj) = {} Accept(obj) = {} ; modify Actor Grab(obj) = { local i; for (i = 1; i <= length(self.possessives); i++) { delword(obj, &adjective, self.possessives[i]); } } Accept(obj) = { local i; for (i = 1; i <= length(self.possessives); i++) { addword(obj, &adjective, self.possessives[i]); } } ; // Returns true if the word is a noun of the object // Used to eliminate adjective-only matches. Necessary because parseNounList // does _not_ seem to return the correct value for PRSFLG_ENDADJ!!! isNounOf: function (word, obj) { local lst = getwords(obj, &noun); if (find(lst, word)) return true; else return nil; } // parseNounPhrase function by Kevin Forchione and Mike Roberts, in response // to a request for help made on rai-f. // Modified to handle 'his' (though not 'my' or other possessives). Also // modified to check that the objects exist within a valid person (ideally the // current 'her' or 'him'). // Further modified to eliminate matches ending in adjectives if there's any // other match. parseNounPhrase: function(wordList, typeList, current_index, complain_on_no_match, is_actor_check) { local i, next_index, next_token, ret, lst = []; local pos = parserGetObj(PO_HER); local found = nil; local gender = &isHer; local eliminateAdj = nil; local lastword = nil; /* let the parser handle noun phrases that don't start with 'her' */ if (wordList[current_index] != 'R' and wordList[current_index] != 'his') return PNP_USE_DEFAULT; if (wordList[current_index] != 'R') { pos = parserGetObj(PO_HIM); gender = &isHim; } /* * 'her' is the last word of the noun phrase, so it is not * being used as a possessive pronoun. */ if (length(wordList) == current_index) return PNP_USE_DEFAULT; /* set the next_index */ next_index = current_index + 1; /* get the next word's type */ next_token = typeList[next_index]; /* * If the next word is an article then 'her' is not being used as a * possessive pronoun. */ if ((next_token & PRSTYP_ARTICLE) != 0) return PNP_USE_DEFAULT; /* * If the next word cannot be an adjective, noun, or plural then * 'her' is not being used as a possessive pronoun. */ if ((next_token & PRSTYP_ADJ) == 0 && (next_token & PRSTYP_NOUN) == 0 && (next_token & PRSTYP_PLURAL) == 0) return PNP_USE_DEFAULT; ret = parseNounList(wordList, typeList, next_index, nil, nil, nil); /* * We don't have a syntactically valid noun phrase, so assume * that 'her' is not being used as a possessive pronoun. */ if (ret == nil) return PNP_USE_DEFAULT; /* * There are 2 cases to examine: no noun phrase or a syntactically * valid noun phrase, but with no matching objects. */ if (length(ret) == 1) /* * No noun phrase. The first word isn't a noun, adjective, * article, etc. */ if (ret[1] == current_index) return PNP_USE_DEFAULT; else { goto noObjects; } /* * We have a valid noun phrase, let's assume that 'her' is being * used as a possessive. We'll restructure the return from * parseNounList() so that it can be returned from * parseNounPhrase(). */ lst += ret[1]; lastword = wordList[ret[2][2]]; /* First we see if there are any objects within the current "her" * object. If so, we will return those possible objects only. * * We also note if the match ended with a noun -- if so, we will later * eliminate all adjective-only matches */ for (i = 3; i <= length(ret[2]); i += 2) { if (not ret[2][i].isIn(pos)) continue; lst += ret[2][i]; lst += ret[2][i+1]; if (isNounOf(lastword, ret[2][i])) eliminateAdj = true; found = true; } /* If there weren't any valid objects within 'her', check for objects * within _any_ female. */ if (not found) { for (i = 3; i < length(ret[2]); i += 2) { if (ret[2][i].location == nil or not ret[2][i].location.(gender)) continue; lst += ret[2][i]; lst += ret[2][i+1]; if (isNounOf(lastword, ret[2][i])) eliminateAdj = true; found = true; } } if (not found) goto noObjects; if (not eliminateAdj) return lst; // Eliminate any match which did not end in a noun. We use "ret" instead // of "lst" for the return value in this case. ret = [] + lst[1]; for (i = 2; i <= length(lst); i+=2) { if (isNounOf(lastword, lst[i])) { ret += lst[i]; ret += lst[i+1]; } } return ret; noObjects: /* * Syntactically valid noun phrase with no matching objects! */ "I don't see any "; for (i = next_index; i <= length(wordList); ++i) { say(wordList[i]); " "; } "here. "; return PNP_ERROR; } parseDisambig: function(str, lst) { local i, tot, cnt; local mystr = str; // Remove possessives (R, his, my, and words ending in 's) from the noun // phrase before asking. This is particularly necessary in the case of R, // because "Which R box do you mean..." is particularly annoying! local match = reSearch('R |his |my |%<%w*\'s%>', str); if (match) { // using length(str) for the length of the second substr will // guarantee that it goes to the end-of-string. A hack, but easier // than calculating. mystr = substr(str, 1, match[1]-1) + substr(str, match[1]+match[2], length(str)); } "Which << mystr >> do you mean, "; for (i = 1, cnt = length(lst) ; i <= cnt ; ++i) { lst[i].thedesc; if (i < cnt) ", "; if (i + 1 == cnt) "or "; } "?"; } #ifdef VERSION // versionTag for Jeff Laing's version.t module possessiveVersion: versionTag author = 'Garth Dighton' func = 'possessive handling' ; #endif VERSION #endif