While I was working on a bug in the Standard Library that so far has taken two years to nail down just what was going wrong, I stumbled over something that’s potentially very confusing. I was running a test game and noticed that I could bypass a before Take rule by doing MOVE BALL TO ME. I extended this to all examples of transferring an object from place to place and thought these should generate a Take as well as a Transfer. It was pointed out to me that on page 89 of DM4 that this is as intended:
For instance, if you only want to prevent an object from entering the player’s possession, you need only block the Take action, unless the object is initially in something or on something, in which case you need to block Remove as well.
I then backed off from the idea of generating a Take in addition to a Transfer. However, I decided to call MOVE BALL TO ME a synonym for TAKE BALL.
I’d like to get some feedback on how to proceed with this. I want the Standard Library to generally agree with PunyInform on how to do things like generating messages with the differences lying chiefly in how PunyInform abbreviates things and omits seldom-used features. I really don’t want there to be disagreement in something as fundamental as taking or moving objects.
As far as I can tell, TransferSub can be made to work in a few different ways:
Move the item from its current location to the target object, possibly firing ##LetGo and ##Receive fake actions to any containers/supporters involved.
or
Move the item to the player, then issue an ##Insert or ##PutOn action to place it in the target object
or
Issue a ##Take action, then move the item to the target object, possibly firing a ##Receive fake action if it’s a container/supporter.
or
Issue a ##Take action, followed by an ##Insert or ##PutOn action.
I think Transfer should generate a ##Take action followed by an ##Insert or ##PutOn action, because:
For almost all objects which the player should be able to transfer from one place to another, the action can be seen as picking the object up and then putting it down in a new place. If there are any active rules in the game which prevent the player from picking up a certain item, or any item, or from getting rid of an item, or from inserting an item in the receiving object, they can’t logically make the requested move either. Issuing a ##Take action followed by a ##Insert or ##PutOn action is the best way to make sure players can’t bypass any such rules put in place by the library or the game author.
DM4 page 89 says "if you only want to prevent an object from entering the player’s possession, you need only block the Take action, unless the object is initially in something or on something, in which case you need to block Remove as well." If ##Transfer moves the object into the player’s inventory without causing a ##Take action, we open up for bugs, as we may not be able to move it into its new position, and then it’s stuck in the player’s inventory, and the statement in DM4 is a broken promise.
If we move an object directly from where it is to the desired destination, this opens up for bugs, as the player is able to move things which the author has tried to block them from picking up with rules for ##Take and ##Remove, based on the above paragraph. They could also react to ##Transfer, but there are several code examples in DM4 which just react to ##Take and ##Remove for objects which the player clearly shouldn’t be able to move.
For the few cases where the player should be able to transfer/move an object but shouldn’t be able to pick it up, special coding will be required anyhow, e.g. a heavy cupboard which can be moved to another corner of the room, or a liquid which can be poured between suitable containers - these cases must handle a lot in the before rules, and they can might as well do all the work there.
tbh, I’m not sure if I have abstracted well the issue, but seems akin to an issue I noticed in TADS/a3Lite, where i found that an “immovable” object can actually be moved from a container to another.
(I generally strive to contain the number of takeable object, giving sensible story-related reason for disallowing indiscriminate TAKE)
perhaps is because the AC is just booted, but the only one sensible reason I can imagine for handling the transferring/blocking a transfer to the player’s inventory is pickpocketing a NPC, and I easily figure that with an alert NPC the setup for a bugfest is on stage…
My apologies if I’m a bit confused, I’m still recovering from a last-minute effort in squashing typos, italianisms and bad english in general… oh, well, time to crack open that 500gr ice-cream tub…
TAKE ICE-CREAM TUB FROM FREEZER
[BUG: The ice cream tub is stuck somewhere in the world model]
STRONG
real adventurer don’t use such language !
DEBUG
[…]
SCRATCH HEAD
You scratch your head about the bug in #Transfer
I agree that ##Take followed by ##Insert/##PutOn is the best approach. I can think of very few cases where an author would want their special rules to affect inserting into something, but not to affect moving something into it.
So this is how the standard library works, in 6.12.7:
Constant story "Test transfers";
Constant headline "^A test game!^";
include "parser.h";
include "verblib.h";
include "grammar.h";
Class Flower;
Object Quarry "Quarry"
with
description "Big quarry.",
has light;
Object -> Box "box"
with
name 'box',
has container open;
Flower -> -> Lily "lily"
with
name 'lily';
Flower -> -> Rose "rose"
with
name 'rose',
before [;
Take, Remove:
"The thorns are terrible. You can't pick it up!";
];
Object -> HotBall "red hot metal ball"
with
name 'red' 'hot' 'metal' 'ball',
before [;
Take, Remove:
"The ball is too hot!";
];
Object -> SmallVase "vase"
with
name 'small' 'vase',
description "Only big enough for one flower.",
capacity 1,
before [;
Receive:
if(~~(noun ofclass Flower))
"The vase is only made for putting flowers in!";
],
has container open;
[ Initialise;
location = Quarry;
print "^^^According to DM4, page 89, it should be enough to block ##Take and ##Remove to make sure that an object
doesn't end up in the player's inventory.^^";
];
Given that, I may consider moving the Standard Library in that direction.
To better keep track of big changes like this, I think it’s time for me to follow @zarf’s suggestion to create a document to track stuff like this. I think it would be best to do this as a document separate from the IF Specs, call it something like “The Inform 6 Library Handbook”, and cover PunyInform as well.
I’m not sure I grasp all the subtleties of the issue, but if the chosen solution goes through a grammar rule for MOVE BALL TO ME, it might deserve to be accompanied by a comment for translators, because grammar rules tend to change a lot once translated.
The MOVE verb grammar implies that an object will be moved from place A to place B without being in the actor’s possession for more than an instant, if at all. MOVE BALL TO ME used to allow the normal ##Take action traps to be bypassed. So I made that a synonym for TAKE. The same trouble happened when place B cannot accept the object being moved around. I think this loophole appeared because of the ##Remove, ##Take, and ##Transfer complications that Inform7 cut down.