Okay, I knew that monkeying around with the inventory settings would be complicated, but I’d thought I’d had it mostly figured out. Basically, I wanted to tweak the inventory lister so that it shows three subdivisions, not just two, so that you’d get a read-out like:
However, upon testing, I find that my code seems to choke if check inventory while I’m holding the sword. Not even wielding, mind you, just holding it. And
it’s only the weapon; the gem gets a free pass, but holding a sword results in “Wrong Number of Arguments”. I’m stumped. What am I missing?
Here’s my code:
#charset "us-ascii"
#include <adv3.h>
#include <en_us.h>
/*A hack to modify the Inventory Lister.*/
modify ThingState
wieldedName(lst) { return listName(lst); }
;
modify Thing
showWieldedItem(options, pov, infoTab)
{
/* show the item, using the worn-listing state name */
showListItemGen(options, pov, infoTab, &wieldedName);
}
showWieldedItemCounted(lst, options, pov, infoTab)
{
/* show the item, using the worn-listing state name */
showListItemCountedGen(lst, options, pov, infoTab, &wieldedName);
}
;
class WieldingLister: InventoryLister
/* show the list item using the "worn listing" name */
showListItem(obj, options, pov, infoTab)
{ obj.showWieldedItem(options, pov, infoTab); }
showListItemCounted(lst, options, pov, infoTab)
{ lst[1].showWieldedItemCounted(lst, options, pov, infoTab); }
;
class WieldingSublister: WieldingLister
/* don't show any prefix, suffix, or 'empty' messages */
showListPrefixWide(itemCount, pov, parent) { }
showListSuffixWide(itemCount, pov, parent) { }
showListEmpty(pov, parent) { }
/* don't show out-of-line contents */
showSeparateContents(pov, lst, options, infoTab) { }
;
actorWieldingSublister: WieldingSublister;
modify actorInventoryLister
/*
* Show the combined inventory listing, putting together the raw
* lists of the items being carried and the items being worn.
*/
showCombinedInventoryList(parent, carrying, wearing, wielding)
{
/* if one or the other sentence is empty, the format is simple */
if (carrying == '' && wearing == '' && wielding == '')
{
/* the parent is completely empty-handed */
showInventoryEmpty(parent);
}
else if (carrying == '' && wielding == '')
{
/* the whole list is being worn */
showInventoryWearingOnly(parent, wearing);
}
else if (wearing == '' && wielding == '')
{
/* the whole list is being carried */
showInventoryCarryingOnly(parent, carrying);
}
//HAX
else if (carrying == '' && wearing == '')
{
/* the whole list is being worn */
showInventoryWieldingOnly(parent, wielding);
}
//Odd one out:
else if (carrying == '' )
{
/* the whole list is being worn */
showInventoryCarryNot(parent, wearing, wielding);
}
else if (wearing == '' )
{
/* the whole list is being worn */
showInventoryWearNot(parent, carrying, wielding);
}
else if (wielding == '' )
{
/* the whole list is being worn */
showInventoryWieldNot(parent, carrying, wearing);
}
else
{
/*
* ALL listings are populated. Count the number of
* comma-separated or semicolon-separated phrases in each
* list. This will give us an estimate of the grammatical
* complexity of each list. If we have very short lists, a
* single sentence will be easier to read; if the lists are
* long, we'll show the lists in separate sentences.
*/
if (countPhrases(carrying) + countPhrases(wearing) + countPhrases(wielding)
<= singleSentenceMaxNouns)
{
/* short enough: use a single-sentence format */
showInventoryShortLists(parent, carrying, wearing, wielding);
}
else
{
/* long: use a two-sentence format */
showInventoryLongLists(parent, carrying, wearing, wielding);
}
}
}
/*
* Count the noun phrases in a string. We'll count the number of
* elements in the list as indicated by commas and semicolons. This
* might not be a perfect count of the actual number of noun phrases,
* since we could have commas setting off some other kind of clauses,
* but it nonetheless will give us a good estimate of the overall
* complexity of the text, which is what we're really after. The
* point is that we want to break up the listings if they're long,
* but combine them into a single sentence if they're short.
*/
countPhrases(txt)
{
local cnt;
/* if the string is empty, there are no phrases at all */
if (txt == '')
return 0;
/* a non-empty string has at least one phrase */
cnt = 1;
/* scan for commas and semicolons */
for (local startIdx = 1 ;;)
{
local idx;
/* find the next phrase separator */
idx = rexSearch(phraseSepPat, txt, startIdx);
/* if we didn't find it, we're done */
if (idx == nil)
break;
/* count it */
++cnt;
/* continue scanning after the separator */
startIdx = idx[1] + idx[2];
}
/* return the count */
return cnt;
}
phraseSepPat = static new RexPattern(',(?! and )|;| and |<rparen>')
/*
* Once we've made up our mind about the format, we'll call one of
* these methods to show the final sentence. These are all separate
* methods so that the individual formats can be easily tweaked
* without overriding the whole combined-inventory-listing method.
*/
showInventoryEmpty(parent)
{
/* empty inventory */
"<<buildSynthParam('The/he', parent)>> {is} empty-handed. ";
}
//HAX
showInventoryWieldingOnly(parent, wielding)
{
/* we're carrying nothing but WIELDING some items */
"<<buildSynthParam('The/he', parent)>> {is} wielding <<wielding>>, but {has} nothing else besides. ";
}
showInventoryWearingOnly(parent, wearing)
{
/* we're carrying nothing but wearing some items */
"<<buildSynthParam('The/he', parent)>> {is} carrying nothing,
and {is} wearing <<wearing>>. ";
}
showInventoryCarryingOnly(parent, carrying)
{
/* we have only carried items to report */
"<<buildSynthParam('The/he', parent)>> {is} carrying <<carrying>>. ";
}
showInventoryCarryNot(parent, wearing, wielding)
{
if (countPhrases(wearing) + countPhrases(wielding)
<= singleSentenceMaxNouns)
{
/* short enough: use a single-sentence format */
showInventoryShortLists1(parent, wearing, wielding);
}
else
{
/* long: use a two-sentence format */
showInventoryLongLists1(parent, wearing, wielding);
}
}
showInventoryWearNot(parent, carrying, wielding)
{
if (countPhrases(carrying) + countPhrases(wielding)
<= singleSentenceMaxNouns)
{
/* short enough: use a single-sentence format */
showInventoryShortLists2(parent, carrying, wielding);
}
else
{
/* long: use a two-sentence format */
showInventoryLongLists2(parent, carrying, wielding);
}
}
showInventoryWieldNot(parent, carrying, wearing)
{
if (countPhrases(carrying) + countPhrases(wearing)
<= singleSentenceMaxNouns)
{
/* short enough: use a single-sentence format */
showInventoryShortLists3(parent, carrying, wearing);
}
else
{
/* long: use a two-sentence format */
showInventoryLongLists3(parent, carrying, wearing);
}
}
showInventoryShortLists1(parent, wearing, wielding)
{
local nm = gSynthMessageParam(parent);
/* short lists - combine carried and worn in a single sentence */
"<<buildParam('The/he', nm)>> {is} wearing <<wearing>>,
and <<buildParam('it\'s', nm)>>{subj} wielding <<wielding>>. ";
}
showInventoryLongLists1(parent, wearing, wielding)
{
local nm = gSynthMessageParam(parent);
/* long lists - show carried and worn in separate sentences */
"<<buildParam('The/he', nm)>> {is} wearing <<wearing>>.
<<buildParam('It\'s', nm)>> wielding <<wielding>>. ";
}
showInventoryShortLists2(parent, carrying, wielding)
{
local nm = gSynthMessageParam(parent);
/* short lists - combine carried and worn in a single sentence */
"<<buildParam('The/he', nm)>> {is} carrying <<carrying>>,
and <<buildParam('it\'s', nm)>>{subj} wielding <<wielding>>. ";
}
showInventoryLongLists2(parent, carrying, wielding)
{
local nm = gSynthMessageParam(parent);
/* long lists - show carried and worn in separate sentences */
"<<buildParam('The/he', nm)>> {is} carrying <<carrying>>.
<<buildParam('It\'s', nm)>> wielding <<wielding>>. ";
}
showInventoryShortLists3(parent, carrying, wearing)
{
local nm = gSynthMessageParam(parent);
/* short lists - combine carried and worn in a single sentence */
"<<buildParam('The/he', nm)>> {is} carrying <<carrying>>,
and <<buildParam('it\'s', nm)>>{subj} wearing <<wearing>>. ";
}
showInventoryLongLists3(parent, carrying, wearing)
{
local nm = gSynthMessageParam(parent);
/* long lists - show carried and worn in separate sentences */
"<<buildParam('The/he', nm)>> {is} carrying <<carrying>>.
<<buildParam('It\'s', nm)>> wearing <<wearing>>. ";
}
showInventoryShortLists(parent, carrying, wearing, wielding)
{
local nm = gSynthMessageParam(parent);
/* short lists - combine carried and worn in a single sentence */
"<<buildParam('The/he', nm)>> {is} carrying <<carrying>>, wearing <<wearing>>, and
<<buildParam('it\'s', nm)>>{subj} wielding <<wielding>>. ";
}
showInventoryLongLists(parent, carrying, wearing, wielding)
{
local nm = gSynthMessageParam(parent);
/* long lists - show carried and worn in separate sentences */
"<<buildParam('The/he', nm)>> {is} carrying <<carrying>>.
<<buildParam('It\'s', nm)>> wearing <<wearing>>.
<<buildParam('It\'s', nm)>> wielding <<wielding>>.
";
}
/*
* For 'tall' listings, we'll use the standard listing style, so we
* need to provide the framing messages for the tall-mode listing.
*/
showListPrefixTall(itemCount, pov, parent)
{ "<<buildSynthParam('The/he', parent)>> {is} carrying:"; }
showListContentsPrefixTall(itemCount, pov, parent)
{ "<<buildSynthParam('A/he', parent)>>, who {is} carrying:"; }
showListEmpty(pov, parent)
{ "<<buildSynthParam('The/he', parent)>> {is} empty-handed. "; }
;
modify DividedInventoryLister
/*
* Show the list. We completely override the main lister method so
* that we can show our two lists.
*/
showList(pov, parent, lst, options, indent, infoTab, parentGroup)
{
/*
* If this is a 'tall' listing, use the normal listing style; for
* a 'wide' listing, use our special segregated style. If we're
* being invoked recursively to show a contents listing, we
* similarly want to use the base handling.
*/
if ((options & (ListTall | ListContents)) != 0)
{
/* inherit the standard behavior */
inherited(pov, parent, lst, options, indent, infoTab,
parentGroup);
}
else
{
local carryingLst, wearingLst, wieldingLst;
local carryingStr, wearingStr, wieldingStr;
/* divide the lists into 'carrying' and 'wearing' sublists */
carryingLst = new Vector(32);
wearingLst = new Vector(32);
wieldingLst = new Vector(32);
foreach (local cur in lst)
{
if(cur.isWornBy(parent))
wearingLst.append(cur);
else if (cur.wieldedBy(parent))
wieldingLst.append(cur);
else carryingLst.append(cur);
}
/* generate and capture the 'carried' listing */
carryingStr = outputManager.curOutputStream.captureOutput({:
carryingLister.showList(pov, parent, carryingLst, options,
indent, infoTab, parentGroup)});
/* generate and capture the 'worn' listing */
wearingStr = outputManager.curOutputStream.captureOutput({:
wearingLister.showList(pov, parent, wearingLst, options,
indent, infoTab, parentGroup)});
/*HAXX MUAHAHAHAHA*/
wieldingStr = outputManager.curOutputStream.captureOutput({:
wieldingLister.showList(pov, parent, wieldingLst, options,
indent, infoTab, parentGroup)});
/* generate the combined listing */
showCombinedInventoryList(parent, carryingStr, wearingStr, wieldingStr);
/*
* Now show the out-of-line contents for the whole list, if
* appropriate. We save this until after showing both parts
* of the list, to keep the direct inventory parts together
* at the beginning of the output.
*/
if ((options & ListRecurse) != 0
&& indent == 0
&& (options & ListContents) == 0)
{
/* show the contents of each object we didn't list */
showSeparateContents(pov, lst, options | ListContents,
infoTab);
}
}
}
/*
* Show the combined listing. This must be provided by each
* language-specific subclass. The inputs are the results (strings)
* of the captured output of the sublistings of the items being
* carried and the items being worn. These will be "raw" listings,
* without any prefix or suffix text. This routine's job is to
* display the final output, adding the framing text.
*/
showCombinedInventoryList(parent, carrying, wearing, wielding) { }
/*
* The recommended maximum number of number of noun phrases to show
* in the single-sentence format. This should be used by the
* showCombinedInventoryList() method to decide whether to display
* the combined listing as a single sentence or as two separate
* sentences.
*/
singleSentenceMaxNouns = 7
/*
* Our associated sub-listers for items begin carried and worn,
* respectively. We'll use these to list our sublist of items being
* worn.
*/
carryingLister = actorCarryingSublister
wearingLister = actorWearingSublister
wieldingLister = actorWieldingSublister
;
Also, some copy-pasta and stuff to illustrate how it fails to work:
DefineTAction(Wield);
VerbRule(Wield)
('wield') singleDobj
: WieldAction
verbPhrase = 'wield/wielding (what)'
;
modify Thing
dobjFor(Wield)
{
verify()
{
illogical('{You/he} cannot wield that. ');
}
}
;
DefineTAction(Unwield);
VerbRule(Unwield)
('unwield') singleDobj
: UnwieldAction
verbPhrase = 'unwield/unwielding (what)'
;
modify Thing
dobjFor(Unwield)
{
verify()
{
illogical('{You/he} {are} not wielding that. ');
}
}
;
class Weapon : Thing 'weapon*weapons' 'weapon'
atk = 2
isWielded = nil
wieldedBy = nil
dobjFor(Drop) maybeRemapTo(isWielded, Unwield, self)
iobjFor(AttackWith)
{
verify(){}
check(){}
action()
{
}
}
dobjFor(Wield)
{
verify(){}
check()
{
if(gActor.wielding)
failCheck('{You/he} already have a weapon. ');
}
action()
{
moveInto(gActor);
gActor.atk += gDobj.atk;
gActor.wielding = true;
gActor.weapon = gDobj;
gDobj.isWielded = true;
gDobj.wieldedBy = gActor;
"{You/he} wield {the dobj/him} as {your/his} weapon. ";
}
}
dobjFor(Unwield)
{
verify(){}
check()
{
if(!gDobj.isWielded)
failCheck('{You/he} are not wielding {the dobj/him} ') ;
}
action()
{
gActor.atk -= gDobj.atk;
gDobj.isWielded = nil;
gActor.wielding=nil;
gActor.weapon = nil;
gDobj.wieldedBy = nil;
"You stop wielding {the dobj/him} as your weapon. ";
}
}
;
sword : Weapon 'sword' 'sword of beta testing'
;
modify Actor
atk = 0
wielding = nil
weapon = nil
;
tunic : Wearable 'tunic' 'tunic'
@me
"A midieval tunic, of the sort often worn by DnD characters. "
wornBy = me
;
gem : Thing 'sparkly gem/jewel' 'sparkly gem'
"It's so sparkly! "
;