I feel like I have gone a long way around when there should be a simpler solution. To make my life easier, I am looking to programmatically derive positional adjectives.
Let’s say I am programming a pub crawl game. A series of beer joints have a variable number of taps (say 1-5) on their respective bars. Most of them derive from common descriptions. I want each pub to auto-populate ‘first tap’ ‘second tap’ ‘third tap’ etc. as names and vocab. The problem, I think, is that by the time the compiler can evaluate the code, the vocabWords are already baked.
My ‘solution’ was to define a base class with a ‘get my order among peers’ routine, use that routine both for name
and additionalVocab
which I one-time updated when the parent was first examined. Here’s what that mess looked like:
class BasicTap : Component // should not be instantiated, use subclasses instead
vocabWords = 'tap/pull/spout*spouts taps pulls'
name = '<<getOrder()>> tap'
getOrder() {
local lst = []; //temp sibling list holder
local orderDesc = ''; //positional descriptive string to return
if (location == nil) return ''; // be weird, a tap floating in space
foreach(local x in location.allContents) //find all neighbor taps
if (x.ofKind(BasicTap)) lst += x;
lst = lst.sort(nil, {a,b: a.pluralOrder - b.pluralOrder} ); // pluralOrder is nice for lists too
local ord = lst.indexOf(self); // find position among neighbors
if (lst.length() == 1) orderDesc = 'single'; // only one
else
if (ord == lst.length()) orderDesc = 'last';
else
switch(ord) {
case 1: orderDesc = 'first'; break;
case 2: orderDesc = 'second'; break;
case 3: orderDesc = 'third'; break;
case 4: orderDesc = 'fourth'; break;
default: "ERROR(BasicTap.getOrder()): too many taps(<<lst.length()>>) defined for <<location.theName>>";
break;
}
return orderDesc;
}
additionalVocab = '' // override when subclass instantiated, will be dynamically updated by Bar with initializeVocabWith(str)
pluralOrder = (sourceTextOrder) // I was betting this wouldn't work, but it did! So far...
// Additional functionality excised...
;
/*
* Individual Tap type subclasses
*/
class pilsnerTap : BasicTap
additionalVocab = '<<getOrder()>> pilsner -'
desc = "A plain handle, releasing a crisp, golden beer. "
;
class ipaTap : BasicTap
additionalVocab = '<<getOrder()>> ipa -'
desc = "A garish handle, releasing an aromatic, hoppy beer. "
;
class sourTap : BasicTap
additionalVocab = '<<getOrder()>> sour -'
desc = "A faux rustic handle, releasing a tart, cloudy beer. "
;
class belgianTap : BasicTap
additionalVocab = '<<getOrder()>> belgian -'
desc = "An Old World handle, releasing a strong, heavier beer. "
;
class stoutTap : BasicTap
additionalVocab = '<<getOrder()>> stout -'
desc = "A culturally insensitive handle, releasing a dark, chewy beer. "
;
/*
*
* The class that will instantiate Taps as Components. Updates tap vocab when first X'd
*
*/
class Bartop : Platform
dobjFor(Examine) {
action() {
if (!described) { // first time only
foreach(local x in allContents) // expand tap vocab
if (x.ofKind(BasicTap)) x.initializeVocabWith(x.additionalVocab);
}
inherited;
}
}
;
Yeah, that’s a lot of code, just so I can elsewhere do this:
bougieBar : Bartop 'bougie bar' 'bougie bar'
"A bar trying way too hard. "
;
+ ipaTap 'rightmost -';
+ ipaTap 'middle -'
desc = "A plain handle, releasing a stinky, hoppy beer. "
;
+ ipaTap 'leftmost -'
desc = "A broken handle, releasing beer indistinguishable from perfume water. "
;
authenticBar : Bartop 'authentic bar' 'authentic bar'
"A bar that oozes authenticity. The neighboring floor is sticky with it. "
;
+ belgianTap;
+ stoutTap;
+ pilsnerTap;
+ sourTap;
//and so on
Long example, lot of coding*, but it feels worth it. I’m putting down a lot of these things (some taps locally overridden in one way or another), and minimizes my cut’n’paste and edit drudgery of positional adjectives. But it also feels like I crawled up my butt a bit to implement it this way. Is there an easier solution I’m totally blind-spotting?
*This example still has a problem. If the player jumps to >X FIRST TAP
before even looking at the bar, they’ll get a deceptive message. That could be addressed by drafting seen
, or on entering bar, or something else. Problem is still kludginess of relying on another object to update its vocab.