#charset "us-ascii" #include #include /* * listControl *. version 0.2 (Beta) : 12-Jul-09 *. by Eric Eve */ //------------------------------------------------------------------------------ /* * listControl provides three new functions: *. stop(lst) *. cycle(lst) *. shuffle(lst) *. * The lst parameter can be supplied either as a single list (in square * brackets) or as a number of parameters separated by commas: in other * words the following two function calls are equivalent: *. *. stop(['screams', 'yells', 'cries again']) *. stop('screams', 'yells', 'cries again') *. * The purpose of these functions is typically to provide minor variations * of wording in larger pieces of text, for example: *. *. "Absolutely not! Bob <>. "; *. * These functions are thus a little similar to the rand() function already * built in to TADS 3, and have been designed to use analogous syntax. *. *. stop() works like a StopEventList *. cycle() works like a CyclicEventList *. shuffle() works like a ShuffledEventList *. * IMPORTANT NOTE. In order for these three functions to work, the * extension has to store data in relation to each list (each three * function needs to keep track of where in the list it has got to). For * this purpose, the extension needs some way of identifying which list is * which, and it does this by looking at the elements of the list. It * follows that if there are two lists with the same elements in your * game, they'll be treated as if they were the same list. This may not * matter for shuffle() but will matter a lot for stop(). * * If this is likely to be an issue for your game, you can make each list * that might otherwise be duplicated unique by adding a first element * that's of a different data type from all the rest. For example, you * could use a number or an object as the first element of a list of * strings to make it a unique list of strings - the stop(), cycle(), and * shuffle() functions will know to ignore this first item in their * output. Thus, one way to ensure a stop() function treats its list as * unique when it's used in a TopicEntry, say, might be to add 'self' as * the first element of the list: * *. "Absolutely not! Bob <>. "; *. * This will work because 'self' will refer to a different object for every * TopicEntry, thus guaranteeing to make the list unique (unless you use * the same list more than once in the same TopicEntry, in which case you * could distinguish them by making the first element [self, 1] then * [self, 2] and so on). */ ModuleID name = 'list control' byline = 'by Eric Eve' htmlByline = 'by Eric Eve' version = '0.2' listingOrder = 70 ; //============================================================================== /* * The listControl object stores three lookup tables for use with the * stop(), cycle() and shuffle() functions, together with some common code * they each use. * * This works by storing a reference to the list for which we want the next * item (in stopping, cyclic or shuffled order) in the appropriate * LookupTable together with the current index value. The next index value * is then calculated according to the kind of list, stored in the table * and returned to the caller. We thus use the LookupTables to associate a * numerical index value with each list. */ listControl: object /* * The LookupTables for use with the stop(), cycle() and shuffle() * functions respectively */ stopTab = nil cycleTab = nil shuffleTab = nil /* * If the first element of the list is not of the same type as the * second, then we assume that the first element is simply a marker to * make the list unique, in which case we don't want to include it * among the items to be returned from the list, so we start with the * second element. */ getFirstIdx(lst) { if(lst.length > 1 && dataType(lst[1]) != dataType(lst[2])) return 2; return 1; } /* * Find the appropriate LookupTable for the kind of list we want to * reference, and create one if one does not already exist. */ getTable(prop) { local tab = self.(prop); if(tab == nil) { self.(prop) = new LookupTable(10,10); tab = self.(prop); } return tab; } /* Return the index of the next item we want from the current list */ getNextIdx(lst, tabProp, nextProp) { local tab = getTable(&tabProp); local idx = tab[lst]; if(idx == nil) idx = getFirstIdx(lst); else { idx++; if(idx > lst.length()) idx = self.(nextProp)(lst); } tab[lst] = idx; return idx; } getNextStopIdx(lst) { return lst.length(); } getNextCycleIdx(lst) { return getFirstIdx(lst); } ; /* * Each of these three functions provides a means of making the stored list * unique; if the first element of the list is of a different datatype * from the second, then the first element will be ignored in creating the * list but stored as part of the key identifying the list. */ /* * In the case of the shuffle function we'll leverage the library's * ShuffledList class. The function creates a new ShuffledList * corresponding to each list it's passed and stores a refence to it in a * LookupTable. The ShuffledList's getNextValue method is then used to * return the next value from the list. */ shuffle([lst]) { if(lst.length == 1 && dataType(lst[1]) == TypeList) lst = lst[1]; local tab = listControl.getTable(&shuffleTab); local shufList = tab[lst]; local modifiedLst = lst; if(shufList == nil) { /* * If the first item in the list is of a different type from the * second, then the first item is simply a marker to make the list * unique, so we don't want it included in the list of items from * which a value will be returned. */ if(lst.length > 1 && dataType(lst[1]) != dataType(lst[2])) modifiedLst = lst.cdr(); shufList = new ShuffledList(modifiedLst); tab[lst] = shufList; } return shufList.getNextValue(); } /* * The next two functions are very similar, so to avoid duplicated code * they simple call the appropriate methods on listControl. */ stop([lst]) { if(lst.length == 1 && dataType(lst[1]) == TypeList) lst = lst[1]; return lst[listControl.getNextIdx(lst, &stopTab, &getNextStopIdx)]; } cycle([lst]) { if(lst.length == 1 && dataType(lst[1]) == TypeList) lst = lst[1]; return lst[listControl.getNextIdx(lst, &cycleTab, &getNextCycleIdx)]; }