| /* Copyright (c) 2000 by Kevin Forchione. All Rights Reserved. */ | |
| /* | |
| * TADS ADV.T/STD.T LIBRARY EXTENSION | |
| * AGAIN.T | |
| * version 2.0 | |
| * | |
| * This module implements a solution to the <<again>> bug that | |
| * exists in TADS 2. <<again>> is limited by the fact that TADS | |
| * repeats the command based on command objects and not player | |
| * command. This can cause problems with commands directed toward | |
| * indistinguishable objects. | |
| * | |
| * You see two apples here. | |
| * | |
| * >eat apple | |
| * That was delicious! | |
| * >g | |
| * You can't repeat that command. | |
| * | |
| * Again.t remedies this by capturing the command word list | |
| * passed to preparseCmd(), then later converting it into a | |
| * command string and prefixing it with the actor vocabulary. | |
| * | |
| * You see two apples here. | |
| * | |
| * >eat apple | |
| * That was delicious! | |
| * >g | |
| * That was delicious! | |
| * >g | |
| * I don't see any apple here. | |
| * | |
| * | |
| * NOTE that capturing the actual words used to address the actor | |
| * would complicate the solution. There is, however, the possibility | |
| * that a parser-generated error message for an "again" command | |
| * that refers to an actor might use words not contained in the | |
| * command. For example: | |
| * | |
| * >x baggins | |
| * blah blah blah | |
| * baggins has left the area. | |
| * | |
| * >g | |
| * There is no bilbo baggins of hobbiton here. | |
| * | |
| *---------------------------------------------------------------------- | |
| * REQUIREMENTS | |
| * | |
| * + HTML TADS 2.5.0 or later | |
| * + Should be compatible with ADV.T, WorldClass, Pianosa | |
| * libraries. Alt users will find that version 1.0.6 implements | |
| * a similar solution. | |
| * + Should be #included after the main library modules. | |
| * | |
| *---------------------------------------------------------------------- | |
| * IMPORTANT LIBRARY INTERFACE AND MODIFICATION | |
| * | |
| * + preparseCmd() | |
| * + preCommand() | |
| * + compoundWords - special note, if you add a new compoundWord | |
| * you must add an equivalent replaceWith() for it in the | |
| * cvtFromCompound() method of the Stringizer class. | |
| * | |
| *---------------------------------------------------------------------- | |
| * COPYRIGHT NOTICE | |
| * | |
| * You may modify and use this file in any way you want, provided that | |
| * if you redistribute modified copies of this file in source form, the | |
| * copies must include the original copyright notice (including this | |
| * paragraph), and must be clearly marked as modified from the original | |
| * version. | |
| * | |
| *------------------------------------------------------------------------------ | |
| * REVISION HISTORY | |
| * | |
| * 06-06-00: Creation. | |
| * 16-06-00: Added conversion of compound words. | |
| */ | |
| #ifndef __AGAIN_MODULE_ | |
| #define __AGAIN_MODULE_ | |
| #pragma C+ | |
| /* | |
| * The preparseCmd() function saves all command word lists except for | |
| * <<again>> or <<g>> in global.cmdWordList. If the command is | |
| * <<again>> or <<g>> we replace it with the stored global command | |
| * string. | |
| * | |
| * It returns true to indicate that processing is to continue with the | |
| * command unchanged. | |
| */ | |
| preparseCmd: function(cmd) { | |
| if (length(cmd) == 1 | |
| && (cmd[1] == 'g' || cmd[1] == 'again')) { | |
| parserReplaceCommand(global.cmdString); | |
| } else { | |
| global.cmdWordList = cmd; | |
| } | |
| return true; | |
| } | |
| /* | |
| * The preCommand() function builds the command string that is then | |
| * stored on global. | |
| */ | |
| preCommand: function(actor, verb, doList, prep, iobj) { | |
| // Build command string only if command was player generated. | |
| if (length(global.cmdWordList)) { | |
| local str; | |
| str = Stringizer.buildCmdString(actor, global.cmdWordList); | |
| global.cmdString = str; | |
| } | |
| } | |
| /* | |
| * The Stringizer class converts a word list to a string. In addition | |
| * it handles the conversion of TADS special words and the appending of | |
| * actor vocabulary to the front of the string to create a command | |
| * string. | |
| */ | |
| class Stringizer: object | |
| buildCmdString(actor, cmdWordList) = { | |
| local actorWordList, actorString, cmdWordString, cmdString; | |
| cmdWordList = self.cvtFromSpec(cmdWordList); | |
| cmdWordString = self.stringize(cmdWordList); | |
| cmdWordString = self.cvtFromCompound(cmdWordString); | |
| /* | |
| * NOTE: getActorVocab() assumes that the actor isn't numbered. If | |
| * you find yourself having difficulty with this option #define | |
| * USE_ACTOR_SDESC. | |
| */ | |
| #ifdef USE_ACTOR_SDESC | |
| actorString = self.getActorSdesc(actor); | |
| #else /* USE_ACTOR_SDESC */ | |
| actorWordList = self.getActorVocab(actor); | |
| actorString = self.stringize(actorWordList); | |
| #endif /* USE_ACTOR_SDESC */ | |
| cmdString = actorString + ', ' + cmdWordString; | |
| return cmdString; | |
| } | |
| cvtFromSpec(wordList) = { | |
| local i, len; | |
| len = length(wordList); | |
| for (i = 1; i <= len; ++i) { | |
| switch(wordList[i]) { | |
| case ',': | |
| wordList[i] = 'and'; | |
| break; | |
| case 'A': | |
| wordList[i] = 'all'; | |
| break; | |
| case 'X': | |
| wordList[i] = 'but'; | |
| break; | |
| case 'I': | |
| wordList[i] = 'it'; | |
| break; | |
| case 'T': | |
| wordList[i] = 'them'; | |
| break; | |
| case 'M': | |
| wordList[i] = 'him'; | |
| break; | |
| case 'R': | |
| wordList[i] = 'her'; | |
| break; | |
| case 'Y': | |
| wordList[i] = 'any'; | |
| break; | |
| case 'B': | |
| wordList[i] = 'both'; | |
| break; | |
| case 'N': | |
| wordList[i] = 'one'; | |
| break; | |
| case 'P': | |
| wordList[i] = 'ones'; | |
| break; | |
| } | |
| } | |
| return wordList; | |
| } | |
| cvtFromCompound(str) = { | |
| str = replaceWith(str, '%<onto%>', 'on to'); | |
| str = replaceWith(str, '%<into%>', 'in to'); | |
| str = replaceWith(str, '%<inbetween%>', 'in between'); | |
| str = replaceWith(str, '%<downin%>', 'down in'); | |
| str = replaceWith(str, '%<downon%>', 'down on'); | |
| str = replaceWith(str, '%<upon%>', 'up on'); | |
| str = replaceWith(str, '%<outof%>', 'out of'); | |
| str = replaceWith(str, '%<offof%>', 'off of'); | |
| str = replaceWith(str, '%<i_wide%>', 'i wide'); | |
| str = replaceWith(str, '%<i_tall%>', 'i tall'); | |
| str = replaceWith(str, '%<waitfor%>', 'wait for'); | |
| str = replaceWith(str, '%<waituntil%>', 'wait until'); | |
| return str; | |
| } | |
| stringize(wordList) = { | |
| local i, len, str = ''; | |
| len = length(wordList); | |
| for (i = 1; i <= len; ++i) { | |
| str += wordList[i]; | |
| if (i != len) | |
| str += ' '; | |
| } | |
| return str; | |
| } | |
| getActorSdesc(actor) = { | |
| local stat, str, actorWordList; | |
| if (actor == parserGetMe()) { | |
| actorWordList = self.getActorVocab(actor); | |
| str = self.stringize(actorWordList); | |
| } else { | |
| stat = outcapture(true); | |
| actor.sdesc; | |
| str = outcapture(stat); | |
| } | |
| return str; | |
| } | |
| getActorVocab(actor) = { | |
| local actorWordList = []; | |
| actorWordList += getwords(actor, &adjective); | |
| if (actor.isThem) | |
| actorWordList += getwords(actor, &plural)[1]; | |
| else actorWordList += getwords(actor, &noun)[1]; | |
| return actorWordList; | |
| } | |
| ; | |
| #ifndef __REPLACEWITH_MODULE_ | |
| #define __REPLACEWITH_MODULE_ | |
| #define RW_REPLACE_ONCE 1 | |
| #define RW_MATCH_WORD 2 | |
| #define RW_MATCH_CASE 4 | |
| #define RW_RET_NIL 8 | |
| /* | |
| * replaceWith(value, target, replacement, flags) | |
| * | |
| * The function searches the value string, replacing the target string | |
| * with the replacement string. | |
| * | |
| * Bit-flags can be passed to control the search. | |
| * | |
| * RW_REPLACE_ONCE replace only one occurrence of the target in the | |
| * value string. | |
| * | |
| * The default for replaceWith() is to replace all occurrences | |
| * of the target in the value string. | |
| * | |
| * RW_MATCH_WORD target must match whole words. For example: | |
| * | |
| * target 'get in' will search for '%<get>% *%<in%>' | |
| * which will match 'get in the chair', but not | |
| * 'get into the chair' | |
| * | |
| * RW_MATCH_CASE target must match the case in value. | |
| * | |
| * The default for replaceWith() is case-insensitive. A target | |
| * string of 'get into' will match on 'GET INTO THE CAR' as | |
| * well as 'Get into the car' unless RW_MATCH_CASE is used. | |
| * | |
| * RW_RET_NIL function returns nil if no match for the target found | |
| * | |
| * The default for replaceWith() returns the value unchanged. | |
| * Using RW_RET_NIL will return the value only if replacement | |
| * occurred; otherwise the function will return nil. | |
| */ | |
| replaceWith: function(value, target, replacement, ...) | |
| { | |
| local ret, new_value = ''; | |
| local valuesave, targetsave, replacementsave; | |
| local flags = 0; | |
| if (argcount > 3) flags = getarg(4); | |
| if ((flags & RW_MATCH_WORD)!= 0) | |
| { | |
| local tmptarget = '%<'; | |
| tmptarget += replaceWith(target, ' ', '%> *%<'); | |
| tmptarget += '%>'; | |
| target = tmptarget; | |
| } | |
| do | |
| { | |
| if ((flags & RW_MATCH_CASE) == 0) | |
| { | |
| valuesave = value; | |
| targetsave = target; | |
| replacementsave = replacement; | |
| value = lower(value); | |
| target = lower(target); | |
| replacement = lower(replacement); | |
| } | |
| ret = reSearch(target, value); | |
| if ((flags & RW_MATCH_CASE) == 0) | |
| { | |
| value = valuesave; | |
| target = targetsave; | |
| replacement = replacementsave; | |
| } | |
| if (ret) | |
| { | |
| local len, tmp = ''; | |
| len = length(value) + 1; | |
| if (ret[1] - 1) | |
| tmp += substr(value, 1, ret[1]-1); | |
| tmp += replacement; | |
| new_value += tmp; | |
| if (len - (ret[1]+ret[2])) | |
| value = substr(value, ret[1]+ret[2], len - (ret[1]+ret[2])); | |
| else | |
| value = ''; | |
| if ((flags & RW_REPLACE_ONCE) != 0) break; | |
| } | |
| else if ((flags & RW_RET_NIL)!= 0 | |
| && new_value == '') | |
| return nil; | |
| } | |
| while( ret != nil); | |
| new_value += value; | |
| return new_value; | |
| } | |
| #pragma C- | |
| #endif /* __REPLACEWITH_MODULE_ */ | |
| #endif /* __AGAIN_MODULE_ */ | |
Xet Storage Details
- Size:
- 10.9 kB
- Xet hash:
- 16487e4fa8722bafcd866d87f3b01870efe8fb9b39160904cfd05dd6ebdfa95c
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.