make the indirect object be implicit

Can you make the indirect object be implicit? I know this happens with direct objects, but the problem is that an indirect object seem to expect the full syntax.

i.e. You are in a room with nothing but a pencil in it. You say “take” without a direct object. It assumes you meant the pencil, and completes the command accordingly.

I’d like that behavior with the INdirect object. For example:

take hoe
hoe dirt
(with garden hoe)
You drag the garden hoe through the dirt, making nice deep furrows.

This involves, I assume, doing something like this:

dobjFor(Hoe) asDobjFor(HoeWith)

But the problem seems to be that the parser, when mapping from the original “Hoe” command that had no indirect object on it, into the two-object verb “HoeWith” that expects an indirect object on it, doesn’t seem to re-run the checks that would have caused it to look around the room to find acceptable implicit objects to use as the indirect object. Instead I get an error when I try to look at the gIobj inside the HoeWith action, because the parser decided to resolve the command into:

“hoe dirt with <hmm, nothing here, I’ll return nil as the indirect object>”

as opposed to

“hoe dirt with <hmm. nothing here, I’d better look for possible implicit objects that might work>”.

I want to say that remapping from a verb that only takes a direct object to one that also takes an indirect object is not allowed, but I’m not 100% sure that’s the case.

Have a look at this page and see if it helps:
tads.org/t3doc/doc/gsg/remap.htm

If you can use remapTo for this, you should be able to get the result you’re after by adding a verify() routine to the iobjFor(HoeWith) section of your indirect object, setting likelihood high enough that it trumps anything else in the area.

Otherwise you can just have a HoeWith verb that takes both a direct object and an indirect object, and give it verb rules such that it also matches 'hoe '. I can dredge up an example; I think there’s at least one of the stock adv3 rules that does this.

https://intfiction.org/t/advanced-verbrules-and-scope/3616/1

Here’s an earlier post I wrote on implementing a TieWith verb with a Tie fallback that covers a missing iobj.

I think if you combine that with boosting the likelihood of particular objects as iobjs for your verb, it will get you what you’re after.

That last suggestion seems to work.

I’ve never had any luck with getting vocabLikelihood or logicalRank to actually work at all. The problem is that the game system only ever seems to care about them when there’s a “tie” from other considerations. i.e. if one item is “nearer” than the other (in your inventory instead of in the room) that seems to take precedence regardless. I ran into this problem when I wanted to have an Unthing be visible from everywhere so that it could be used as an object even when it’s not there (i.e. “gather leaves into pile”, when “pile” won’t exist until the gather command is done so the noun “pile” doesn’t work unless there’s something called “pile” in reach. So I tried making an Unthing called ‘pile’ which was also a MultiLoc and existed in every room so it could be referred to anywhere. The problem is that after making an object called pile that is a real Thing that does exist, from then on the Unthing pile always took precedence over any actual real pile in the room, stupidly enough, and so any attempt to do anything with the pile kept giving the generic Unthing response “you don’t see that here”.

No matter what I did to the vocabLikelihood or the logicalRank it just didn’t matter. the Unthing always was picked by the parser in preference over everything else, without even asking for a disambigation prompt.

Eventually I found I could escape this mess by not trying to make it both an Unthing and a Multiloc. For some reason the problem was making it a Multiloc was overriding making it an Unthing. So instead I made it JUST an Unthing and then made it always available by setting the Unthing’s location to gPlayerChar rather than using the MultiLoc means of making it usable everywhere. I still don’t like this solution because I don’t like having an Unthing in inventory, but since I couldn’t solve the problem via the logicalRank or the vocabLikelihood that’s what I had to resort to.

The problem with logicalRank and vocabLikelihood is this: You absolutely cannot use them to downgrade the parser’s preference to use an object one of who’s superclasses already has a dObjFor defined for the action in question. I had to read the adv3 code for a while to work out what was happening, but it’s this:

vocabLikelihood can never be used to override logicalRanks. If the logicalRank between two choices differs, vocabLikelihood is utterly ignored. It exists purely for trying to break ties between logicalRank. If there’s something else hidden inside the superclasses that’s causing you to get differing logicalRanks, no amount of fiddling with vocabLikelihood will make one bit of difference, you have to change the logicalRank, not the vocabLikelihood. Okay, so I then tried to change the logicaRanks. But the problem is that you can’t do that in a generic applied-to-every-verb sort of way. You have to pick each and every verb you want to override it for because dobjFor(Default) never overrides a superclass’es dobjFor([some specific verb]).

At that point I was tired of dealing with it and just gave up on it and accepted that I had to stop using MultiLoc with Unthing because MultiLoc broke Unthing’s tendency to want to avoid matches if at all possible.

Interesting. It’s possible if you had changed the inheritance order for your class that it would have worked; there’s a rule about where Thing-derived classes need to be that I always have to look up. It’s either first or last. :slight_smile:

Subclasses can override a parent’s logical rank by including a dobjFor(verb) with either an empty verify block or cherry-picked portions of the parents. This is because dobjFor and friends are macros which define a slew of methods, any one of which can be overridden on a child like you’d expect. If you don’t include the other blocks - check, action etc - it leaves the inherited value in place.

That should be enough to zero out an inherited preference; I’d be curious to hear if you tried that and it didn’t work.

Rather than mess around with vocabLikelihood and all that, you might want to just put a nestedAction or a replaceAction in the action() block. Or just use a check routine that checks whether the player is carrying the hoe when she attempts to use the “hoe” (or “dig”) command.

To do it the way you imagined it, you should override objInScope() in your GATHER action:

objInScope(obj)
{
    if (obj == fakePile) {
        return true;
    }
    inherited;
}

Then, you can have a ‘fakePile’ object that’s a normal Thing and put it in the nil location.

However, the right way to do this is having the correct syntax for GATHER to begin with. It should be a TAction with a VerbRule like this:

VerbRule(Gather)
    'gather' dobjList 'into' 'pile'
    : GatherAction
    verbPhrase = 'gather/gathering (what) into a pile'
;

You don’t need a fake pile object. You need verb grammar that understands “pile”. You can then generate a real pile object in the action handler and place it in the current location when the player gathers something into a pile.

The way I solved it was to do bcressy’s solution. I made a second variant of the grammar rule for Gather that said when no indirect object or preposition is used it would ask for an indirect object right there in the grammar rule. Then it executed the same action as the version that has the indirect object so none of the iobjFor(HoeWith) rules had to be changed.