Attachables

The attachables module provides a couple of classes to facilitate attaching objects to one another in simple cases (so if you don't have any need to attach objects to each other in your game right now you can skip this section and come back to it later). The adv3Lite implementation is both simpler and easier to use than the adv3 Attachable class, but handles a far more restricted range of cases (for the sake of keeping things simple). Also, unlike the adv3 Attachable framework, in adv3Lite attachment is not a symmetrical arrangement, i.e. ATTACH A TO B does not mean the same thing as ATTACH B to A. Moreover in adv3Lite attachment is (mainly) implemented as a many-to-one relationship, that is you can attach many As to one B using commands of the form ATTACH A to B (the exception is the Attachable class described below, which allows a many-to-many attachment relationship).

We can make this clearer by means of a concrete example. Suppose we have a fridge magnet. We can then ATTACH MAGNET TO FRIDGE. The magnet is then considered as attached to the fridge rather then vice versa. Since the fridge is the dominant or larger object in this attachment relationship, it could have several magnets attached to it, for example a round magnet, a square magnet, and a star-shaped magnet. All three magnets could be attached to the fridge in turn with the commands ATTACH ROUND MAGNET TO FRIDGE, ATTACH SQUARE MAGNET TO FRIDGE, and ATTACH STAR MAGNET TO FRIDGE. Either before or after being attached to the fridge the magnets could in their turn have objects attached to them, e.g. ATTACH PAPERCLIP TO ROUND MAGNET and ATTACH DRAWING PIN TO ROUND MAGNET. After all these commands had been issued, the three magnets would be attached to the fridge, while the paperclip and the drawing pin would be attached to the round magnet.

The base class for implementing this type of attachment in adv3Lite in the SimpleAttachable. In order to attach two objects, both must defined as SimpleAttachables (or as a subclass thereof). You should then define the allowableAttachments property on the major item (the one things are to be attached to, such as the fridge in our previous example) with a list of objects that can be attached to it (e.g. [roundMagnet, squareMagnet, starMagnet]). For example, if we had just one magnet we wanted to be able to attach to a fridge we might define:


+ fridge: SimpleAttachable 'fridge; large white; refrigerator door'
    "It's a large, white floor-standing refrigerator. "
    remapIn: SubComponent { isOpenable = true }
    allowableAttachments = [magnet]
    isFixed = true
    isListed = nil
;

++ magnet: SimpleAttachable 'small magnet; red maple; leaf'
    "It's red and shaped like a maple-leaf. You must have picked it up on your
    last trip to Canada. "
    attachedTo = fridge
;

In this example, the magnet starts out attached to the fridge, which is why we define attachedTo = fridge and locate the magnet in the fridge (with the ++ notation; note also that to make sure the magnet is on the outside of the fridge we define the interior of the fridge on its remapIn property). If you didn't want the magnet to start out attached to the fridge you'd just locate it wherever you want it to start out and leave its attachedTo property undefined. The above example does, however, illustrate a couple of useful points. First, it shows how you can define an object as starting off attached, and secondly it calls attention to the fact that if you attach one object to another the first object ends up located in the second (which ensures that the first object will move around with the second if the second object is moved), and that when an object is attached to another object the first object's attachedTo property is set to the second object.

More generally, the properties and methods of SimpleAttachable you might commonly want to use are:

The library defines three subclasses of SimpleAttachable: AttachableComponent, NearbyAttachable and Attachable.

An AttachableComponent is a SimpleAttachable that's treated as a component of the item to which its attached (the handle of a knife, say). An AttachableComponent starts out with its isFirmAttachment property set to true, and its allowDetach property set to nil. It also defines an initiallyAttached property which, if true (the default) means that the Component starts out attached to its immediate container. Moreover, the locType of an attached AttachableComponent is PartOf. If an AttachableComponent starts out as a separate item (e.g. a handle not yet attached to a knife) it effectively becomes a part of (i.e. a component of) the item its attached to when it is attached (e.g. ATTACH HANDLE TO KNIFE would effectively make the handle part of the knife, assuming the handle was an AttachableComponent and the knife a suitably defined SimpleAttachable). Note that if the handle started out attached to the knife and never needed to be reattached to it during the game, there would be no need to make the knife a SimpleAttachable; the knife could then just be a Thing.

A NearbyAttachable is a SimpleAttachable that's moved into the location of the object it's attached to, instead of becoming located within the other object. (This might be useful, say, for connecting lengths of hose or cable together, or assembling a device out of its components). You can override the attachedLocation and detachedLocation properties (on the object to be attached) to tweak this behaviour; for example you could set both to location (meaning the location of the attached object) if you don't want attaching it to the other object to move it at all.

An Attachable is a NearbyAttachable that can be attached to more than one thing at time (as well as having more than one thing attached to it). This is intended for more complex cases than the SimpleAttachable model can handle, such as a cable that's needed to connect a piece of electrical equipment to a power outlet (and so needs to be plugged into both) or a rope used to tie two or more objects together (which needs to be attached to all of them). In addition to the methods and properties it inherits from SimpleAttachable via NearbyAttachable, the Attachable class defines the following:


PlugAttachable

The PlugAttachable class is a mix-in class designed to be used together with either SimpleAttachable or NearbyAttachable. This allows an object to be Plugged into or Unplugged from another object. It's then attached to the other object, but described as being plugged into it. Attaching one PlugAttachable to another is equivalent to plugging it in. For example:

+ plug: PlugAttachable, NearbyAttachable 'electric plug'    
;

+ socket: PlugAttachable, NearbyAttachable, Fixture 'power socket'
    allowableAttachments = [plug]
;

The number of items that can be plugged into something (the socket) at any one time is controlled by the socket's socketCapacity property, which is 1 by default.

If you want to define an object that can be plugged in and unplugged without specifying a particular socket, you can use the PlugAttachable mix-in with an ordinary Thing class and define its needsExplicitSocket property as nil, e.g.:

+ tv: PlugAttachable, Switch, Fixture 'television;;tv'
    "It's currently <<if isOn>>on<<else>>off<<end>>, not that it makes much
    difference to the quality of what appears on the screen. "

    specialDesc = "A TV lurks in one corner of the room. "
    needsExplicitSocket = nil
    
    dobjFor(SwitchOn)
    {
        check()
        {
            if(!isPluggedIn)
                "It's not plugged in. ";
        }
    }
    
    makePlugged(stat)
    {
        inherited(stat);
        if(!stat)
            makeOn(nil);
    }
;