I investigated this further with the following test case:
Constant Story "DROPSUB IMPLICIT TAKE";
Constant Headline "^An Interactive Investigation^";
Include "Parser";
Include "VerbLib";
Object Start_Room "Start Room"
with description "This is the starting room.",
has light;
Object tin "metal tin"
with name 'metal' 'tin',
has container openable;
Object -> mint "breath mint"
with name 'breath' 'mint',
has edible;
[ Initialise;
location = Start_Room;
move tin to player;
];
Include "Grammar";
This has the following behavior:
I had expected drop to have similar behavior as eat, implicitly taking the mint out of the tin.
However, reading ImplicitTake more carefully, I see that the first few lines are:
[ ImplicitTake obj
res ks supcon;
switch (metaclass(obj)) { Class, String, Routine, nothing: rfalse; }
if (obj in actor) rfalse;
if (action_to_be == ##Drop) rfalse;
It seems that, in the case of ##Drop, ImplicitTake will always return false before changing the model world in any way.
I overlooked this because, in the program that I referred to in my previous post, I had created a new action with its code based on the existing DropSub impl, so action_to_be wasn’t ##Drop. In the case of regular ##Drop, the distinction that I made between multiheld/multiexcept and other tokens is irrelevant since the parser’s invocation of ImplicitTake always matches this action_to_be test and returns false, so DropSub’s ImplicitTake line is called either way.
In light of this, rather than the ~~ImplicitTake() check in DropSub being reversed, it seems that it’s instead superfluous and that the same effect could be achieved with:
if (noun notin actor) return L__M(##Drop, 2, noun);
Evidently, the library explicitly does not want ##Drop ever to do an implicit take, although it’s unclear to me why this should be the case given how ##Eat works. I think that maybe it’s to prevent the parser’s multiheld/multiexcept ImplicitTake, when the user types “drop ”, from producing “(first taking the foo) Dropped.” ImplicitTake could deal with that by extending its acton_to_be check to:
if (action_to_be == ##Drop && obj in parent(actor)) rfalse;
This should allow the “drop ” case to produce “the foo is already here”, while allowing items that are indirectly contained in the actor to be implicitly taken and dropped.
All that being said, I’m not sure to what extent existing games rely on the old behavior or if there’s a mandate to improve I6 library behavior (assuming that we can agree on what constitutes an improvement) vs. just fixing bugs.