Replace an action

Dear all,

I know how to simply override a system action, but how do I override it with an altered grammar? The command I want to parse is “remove X with Y”, so I need to override the “Remove” function, but with an added object. In Inform 6 that would be “Extend ‘remove’ first * ‘with’ noun → My_Remove_Routine;”

Thanks and kind regards,
Grues

1 Like

You want to define a new action that takes both a direct and indirect object. In TADS3 the macro you probably want for this is DefineTIAction.

Declaring the action itself is straightforward:

DefineTIAction(RemoveWith);

The you need to declare a VerbRule for the action, something like:

VerbRule(RemoveWith)
        'remove' singleDobj 'with' singleIobj
        : RemoveWithAction
        verbPhrase = 'remove/removing (what) (with what)'
        omitIobjInDobjQuery = true
        askDobjResponseProd = singleNoun
        askIobjResponseProd = withSingleNoun
;

In this case the askDobjResponseProd and askIobjResponseProd properties are superfluous, because there’s an existing action (RemoveAction) that will end up being matched if the player uses >REMOVE [object] without an indirect object. If you don’t want that to happen (and you want to disable the stock RemoveAction as well) let me know.

Adding a new action you probably want to declare a stock behavior for it on Thing, to provide a useful failure message for objects that don’t implement it.

First declare the failure messages (you can hardcode them, but creating new library messages and using them makes maintenance easier):

modify playerActionMessages
        cantRemoveWithThat = '{You/he} can\'t remove {that dobj/him}. '
        cantRemoveWithThatIobj = '{You/he} can\'t remove anything
                with {that dobj/him}. '
;

…and then add the default handing to Thing:

modify Thing
        dobjFor(RemoveWith) {
                verify() { illogical(&cantRemoveWithThat); }
        }
        iobjFor(RemoveWith) {
                verify() { illogical(&cantRemoveWithThatIobj); }
        }
;

I don’t know what kind of behavior you want to implement, but you can now individually override the dobjFor(RemoveWith) and iobjFor(RemoveWith) stanzas to create different results when the action is used with different direct and indirect objects. Example:

pebble: Thing 'small round pebble' 'pebble'
        "A small, round pebble. "
        dobjFor(RemoveWith) {
                verify() {}
                action() {
                        "This is the pebble success message. ";
                }
        }
;
rock: Thing '(ordinary) rock' 'rock'
        "An ordinary rock. "
        iobjFor(RemoveWith) {
                verify() {}
                action() {
                        "This is the rock success message. ";
                }
        }
;

In this case the pebble can be used as the direct object and the rock can be used as the indirect object and each will display a message when this is done.

Putting this all together:

#charset "us-ascii"
#include <adv3.h>
#include <en_us.h>

modify playerActionMessages
        cantRemoveWithThat = '{You/he} can\'t remove {that dobj/him}. '
        cantRemoveWithThatIobj = '{You/he} can\'t remove anything
                with {that dobj/him}. '
;

startRoom: Room 'Void' "This is a featureless void. ";
+me: Person;
+pebble: Thing 'small round pebble' 'pebble'
        "A small, round pebble. "
        dobjFor(RemoveWith) {
                verify() {}
                action() {
                        "This is the pebble success message. ";
                }
        }
;
+rock: Thing '(ordinary) rock' 'rock'
        "An ordinary rock. "
        iobjFor(RemoveWith) {
                verify() {}
                action() {
                        "This is the rock success message. ";
                }
        }
;
+stone: Thing '(nondescript) stone' 'stone'
        "A nondescript stone. "
;

versionInfo: GameID;
gameMain: GameMainDef initialPlayerChar = me;

DefineTIAction(RemoveWith);
VerbRule(RemoveWith)
        'remove' singleDobj 'with' singleIobj
        : RemoveWithAction
        verbPhrase = 'remove/removing (what) (with what)'
        omitIobjInDobjQuery = true
        askDobjResponseProd = singleNoun
        askIobjResponseProd = withSingleNoun
;

modify Thing
        dobjFor(RemoveWith) {
                verify() { illogical(&cantRemoveWithThat); }
        }
        iobjFor(RemoveWith) {
                verify() { illogical(&cantRemoveWithThatIobj); }
        }
;

Transcript:

Void
This is a featureless void.

You see a stone, a pebble, and a rock here.

>remove stone
(from the void)
Taken.

>undo
Taking back one turn: "remove stone".

Void
This is a featureless void.

You see a stone, a pebble, and a rock here.

>remove rock with stone
You can't remove that.

>remove pebble with stone
You can't remove anything with that.

>remove rock with pebble
You can't remove that.

>remove pebble with rock
This is the rock success message.  This is the pebble success message.

4 Likes

Thanks so much, jbg! Took me a while to get it to work, but everything’s fine now, and thanks to you I learned a lot on the way. Very, very much appreciated! <3

2 Likes

No problem.

Although now that I think about it, the failure messages would be better as something like:

modify playerActionMessages
        cantRemoveWithThat = '{You/he} can\'t remove {the dobj/him}. '
        cantRemoveWithThatIobj = '{You/he} can\'t remove anything
                with {the iobj/him}. '
;

…which would get you…

>remove stone with pebble
You can't remove the stone.

>remove pebble with stone
You can't remove anything with the stone.

…which is more informative than the generic "that"s in the first version.