A Handy Kit

An interactive fiction by Andrew Plotkin (2006) - the Inform 7 source text

Home page

Contents
Previous
Next

Complete text
Chapter 4 - Rules for Connectable Stuff

Color is a kind of value. The colors are black, red, purple, blue, green, yellow, orange, brown, and mauve.

A module is a kind of tool. Understand "link" or "minus" as a module.
A module has a color. Modules are usually mauve. Understand the color property as describing modules.

A trigger is a kind of tool. Understand "link" or "plus" as a trigger.
A trigger has a color. Triggers are usually black. Understand the color property as describing triggers.

A remote is a kind of tool.
A remote has a color. Remotes are usually black. Understand the color property as describing remotes.

A thing can be connectable. A tool is usually connectable.

[The connection between a trigger and a module is a reciprocal relation. This is slightly too broad, since this definition of the relation will permit connectivity between two triggers or two modules. We'll just have to be careful not to do that.]
Connectivity relates one tool to another (called the partner). The verb to interface (it interfaces, they interface, they interfaced, it is interfaced, it is interfacing) implies the connectivity relation.

Definition: a tool is connected if it interfaces something.

[For the connection between a remote and a trigger, I decided to make two one-way relations, one defined in terms of the other. I had no particular reason for this.]
Transmission relates one remote to one trigger. The verb to notify (it notifies, they notify) implies the transmission relation.
Reception relates a trigger (called Y) to a remote (called X) when X notifies Y. The verb to attend (it attends, they attend) implies the reception relation.

Contacting it with is an action applying to two things.
Understand "touch [something] to [something]" as contacting it with.
Understand "touch [something] on [something]" as contacting it with.
Understand "touch [something] with [something]" as contacting it with (with nouns reversed).
Understand "connect [something] to/on/onto/with/into [something]" as contacting it with.
Understand the commands "link", "plug", "join", and "affix" as "connect".
Understand the command "attach" as something new. Understand "attach [something] to/on/onto [something]" as contacting it with.
Understand "tie [something] onto [something]" as tying it to.
Instead of tying something (called X) to something (called Y), try contacting X with Y.

Instead of putting a tool (called X) on a tool (called Y), try contacting X with Y.

Detaching is an action applying to one thing.
Understand "detach [something]" as detaching.
Understand the commands "unlink", "unplug", "disconnect", and "free" as "detach".
Detaching it from is an action applying to two things.
Understand "detach [something] from [something]" as detaching it from.

[Handy trick here. We want to modify the object's name in inventory listings and room descriptions (including sublists inside containers), but not during action commands. Solution: "while listing contents of some object". Note that "...of something" is not sufficient, because rooms are not "things"!]
After printing the name of a module (called mod) while listing contents of some object:
    If mod interfaces something (called trig),
        say " (connected to [a trig])"

Check contacting it with:
    If the second noun is connectable and the noun is not connectable,
        instead try contacting the second noun with the noun;
    if the noun is connectable,
        instead try connecting the noun with the second noun.
        
Report contacting it with:
    instead say "Nothing happens."

Report contacting it with when the noun is the second noun:
    instead say "You can't touch something to itself."

This is the can't disconnect what isn't connected rule:
    if the noun is not connected,
        instead say "[The noun] isn't connected to anything."

This is the can't disconnect what's connected elsewhere rule:
    if the noun is not the partner of the second noun,
        instead say "[The noun] is connected to [the partner of the noun], not to [the second noun]."

[I really like expressing the conditions here with rules, like I've done. Sure, it's analogous to using subroutines in I6. But it's tidy.]
Check detaching when the noun is a module:
    abide by the can't disconnect what isn't connected rule;
    instead try disconnecting the noun from the partner of the noun.

Check detaching when the noun is a trigger:
    abide by the can't disconnect what isn't connected rule;
    instead try disconnecting the partner of the noun from the noun.

Check detaching it from when the noun is a module:
    abide by the can't disconnect what isn't connected rule;
    abide by the can't disconnect what's connected elsewhere rule;
    instead try disconnecting the noun from the partner of the noun.
    
Check detaching it from when the noun is a trigger:
    abide by the can't disconnect what isn't connected rule;
    abide by the can't disconnect what's connected elsewhere rule;
    instead try disconnecting the partner of the noun from the noun.


Report detaching:
    instead say "There's no clear way to do that."
Report detaching it from:
    instead say "There's no clear way to do that."

[Connecting is a "fake action", in I6 terms; it isn't triggered by any player commands. It occurs only via a "try connecting..." phrase. I would have used an activity, except that an activity can apply to at most one thing.]
Connecting it with is an action applying to two things.

[I'm making this a general rule (no "when" clause) so that it sorts last in the rulebook of "check connecting it with". This may be a barbarism -- maybe I should name it and then say things like "the lockpick can't connect with itself rule is listed before the stuff can't connect with itself rule." For now, I won't bother.]
Check connecting it with (this is the stuff can't self-connect rule):
    If the noun is the second noun,
        instead say "You can't connect something to itself."
        
Report connecting it with:
    Say "Those don't connect."

Check connecting it with when the noun is a trigger (this is the trigger connection check rule):
    If the noun is connected,
        instead say "[The noun] is already connected to [the partner].";
    if the second noun is a trigger,
        instead say "You can't connect two positive links together.";
    if the second noun is a remote,
        instead carry out the complaining about no link on activity with the second noun;
    if the second noun is a connected module,
        instead say "[The second noun] is already connected to [the partner of the second noun]."
        
Check connecting it with when the noun is a module (this is the module connection check rule):
    If the noun is connected,
        instead say "[The noun] is already connected to [the partner].";
    if the second noun is a module,
        instead say "You can't connect two negative links together.";
    if the second noun is a remote,
        instead carry out the complaining about no link on activity with the second noun;
    if the second noun is a connected trigger,
        instead say "[The second noun] is already connected to [the partner of the second noun].";
    if the second noun is a trigger,
        instead try connecting the second noun with the noun.
    
Check connecting it with when the noun is a remote (this is the remote connection check rule):
    instead carry out the complaining about no link on activity with the noun.

[This shouldn't have to be a procedural rule, but I couldn't get the "Rule X is listed after rule Y" declaration to work. Bug filed.]
Procedural rule:
    Move the trigger connection check rule to after the stuff can't self-connect rule;
    move the module connection check rule to after the stuff can't self-connect rule;
    move the remote connection check rule to after the stuff can't self-connect rule.

Carry out connecting when the noun is a trigger and the second noun is a module:
    Now the noun interfaces the second noun;
    relocate the second noun based on the noun;
    now the noun is part of the second noun;
    change the color of the noun to the color of the second noun;
    if something (called trans) notifies the noun,
        change the color of trans to the color of the second noun.
            
Report connecting when the noun is a trigger and the second noun is a module:
    say "You connect [the noun] to [the second noun]. [The noun] turns [color of noun] to confirm the match";
    if the noun attends something (called trans) begin;
        if the trans is visible,
            say ", and [the trans] turns [color of trans] as well";
    end if;
    say ".[conditional paragraph break]";
    if the noun is currently active begin;
        change the visible effect to zero;
        activate the second noun;
    end if;
    rule succeeds.
    
[Another "fake action", parallel to connecting.]
Disconnecting it from is an action applying to two things.

Check disconnecting it from (this is the disconnection assertions rule):
    If the noun is not a module,
        instead say "(BUG) [The noun] is not a module!";
    if the second noun is not a trigger,
        instead say "(BUG) [The second noun] is not a trigger!";
    if the noun is not the partner of the second noun,
        instead say "(BUG) [The noun] and [the second noun] are not connected properly!";
    if the second noun is not the partner of the noun,
        instead say "(BUG) [The second noun] and [the noun] are not connected properly!"
        
Carry out disconnecting it from:
    now the noun is not interfaced by the second noun;
    now the player carries the second noun.
    
Report disconnecting it from:
    Say "You disconnect [the noun], and take [the second noun] as it turns black again";
    if the second noun attends something (called trans),
        if trans is visible, say ". [The trans] turns black as well";
    say ".[conditional paragraph break]";
    if the second noun is currently active begin;
        change the visible effect to zero;
        deactivate the noun;
    end if;
    rule succeeds.
        
Instead of taking a trigger when the noun is connected:
    try taking the partner of the noun.
    
Instead of dropping a trigger when the noun is connected:
    try dropping the partner of the noun.

Report taking a module when the noun is connected:
    instead say "You take [the noun] (and [the partner of the noun] connected to it)."

Report dropping a module when the noun is connected:
    instead say "You drop [the noun] (and [the partner of the noun] connected to it)."

[I suffered some angst when trying to figure out how to implement this. Should it be an activity, a rule, a rulebook, or a phrase? I decided that I couldn't use a rule or rulebook, because I needed to pass in an argument. (You can't "follow" a rule/rulebook and provide an object for the rule to work on.) A phrase is suboptimal because the calling rule has to specify "rule fails". (Or am I wrong? I thought I tried it.) An activity seems to work, although I don't know why it's different from a phrase. I think an action would have worked too.]
Complaining about no link on something is an activity.
Rule for complaining about no link on something (called item):
    [The only way I could get a binding on the item's transmitter was this "if" statement.]
    if the item notifies something (called trig),
        say "[The item] doesn't have a link; it works through [the trig].";
    otherwise
        say "[The item] doesn't have a link."
    
To say tool status (item - tool):
    if the item is connected,
        say ", which is connected to [the partner]"

To relocate (item - tool) based on (other item - tool):
    if the player carries the item or the player carries the other item begin;
        now the player carries the item;
        stop;
    end if;
    if the player encloses the other item begin;
        move item to the holder of the other item;
        stop;
    end if;
    if the player encloses the item begin;
        stop;
    end if;
    move item to the holder of the other item.

Commanding on is an action applying to nothing. Understand "zap" as commanding on.
Commanding off is an action applying to nothing. Understand "pow" as commanding off.
Carry out commanding on: say "You say the keyword."
Carry out commanding off: say "You say the keyword."

[Activities used by the timer and voice triggers. (The other triggers are simple enough not to need it.) I originally used a fake action here, but that comes with baggage about reachability which I don't need. I just want some rules.]
Engaging something is an activity.
Disengaging something is an activity.

[This is a half-clever trick. I need to keep track of whether remote activation produces any kind of visible effect. To do this, I sprinkle say "[effective]" substitutions into the various result messages. This substitution doesn't actually print anything; it just changes the visible effect variable.]
The visible effect is a number that varies.
To say effective:
    change visible effect to one.

[Phrases which will define all module activity. The default values should not appear in final gameplay; they are placeholders for activity that I haven't written yet.]
[Unfortunately, phrase precedence doesn't work right! (Bug filed.) I am working around this by having the activate/deactivate phrases trigger activities called activate-tmp/deactivate-tmp. The boolean argument "momentarily" will be shoved into a global variable. (An integer variable, since there are no boolean global variables.) I am not proud of this, but activity precedence works, so that's what I'm using.]
To activate (item - module), momentarily:
    if momentarily, change momentarily-tmp-var to one;
    otherwise change momentarily-tmp-var to zero;
    carry out the activating-tmp activity with item.

To deactivate (item - module):
    carry out the deactivating-tmp activity with item.

Momentarily-tmp-var is a number that varies.
To decide whether momentarily-tmp:
    If momentarily-tmp-var is zero, decide no;
    otherwise decide yes.
To decide whether not momentarily-tmp:
    If momentarily-tmp-var is zero, decide yes;
    otherwise decide no.
Activating-tmp something is an activity.
Deactivating-tmp something is an activity.

Rule for activating-tmp something (called item):
    if momentarily-tmp, say "[effective](BUG) [The item] activates momentarily.";
    otherwise say "[effective](BUG) [The item] activates."
    
Rule for deactivating-tmp something (called item):
    say "[effective](BUG) [The item] deactivates."

[Again, phrase precedence doesn't seem to be good enough to let me put rules on each item. So I'm doing this with a simple agglutinated "if" list.]
To decide whether (item - thing) is currently active:
    if the item is the toggle switch and the toggle switch is on, decide yes;
    if the item is the voice module and the voice transmitter is on, decide yes;
    if the item is the timer and the timer is on, decide yes;
    decide no.