It was a complete mystery. My beautifully implemented Model::World test had the following line of code:
$player->put($box, $ring);
And that dies with the message:
You can't put anything in the player
The intent was, when a player receives a message, it assumes it has a verb, an optional object, and zero or more arguments after that. However, the box, ring, and player classes are all subclasses of the Thing class. This was bad. Everytime I add a possible "Verb" to the box class, player should not automatically inherit it. Instead, the player should always be able to inspect a thing and figure out what it can do. I can override put in the player class, but every time I add a verb for the box class, I have to remember to override it in the player class. This is wrong.
Instead, I need to create an "abstract thing" class which provides only the tiniest amount of code. Then the player can inherit from the abstract thing class and a "item" (bad name) or other class can also inherit from that and the box and ring inherit from the item class. Thus I avoid bad inheritance.
The comes a real problem: what can a player do? A player can "do" any verb the player defines. These are often intransitive verbs, verbs which do not take a direct object. For example, "Johns jumps" has an intransitive verb. A player can also "do" any verb a thing allows. If a Box class supplies a "break" method (and verb), then "John breaks the box" is allowed and this calls the "box->break" method.
The problem comes in when a verb can be used either transitively or intrasitively. A player can just "look around" and we have an intransitive verb. What if a player looks at another player? Now it's not an intransitive verb. I can't just "player2->look". So now when actions are performed, I'll have to consider whether the invocant is the subject or the object of the action. I'm sure there is a simple way of doing this, but I'm going to have to mull over this for a while.
sub look {
my($self, $object) = @_;
if ($self == $object) { ... }
else { $object->look($object) }
}
It sounds like you have two different methods, look_around
and look_at
. The former doesn't take an object, the latter does.