! SENSES An Inform Library by L. Ross Raszewski
! To handle sensory perception. Written in 5.5,
! Easily portable to 6.0 (I hope)
! Version 5/1 9-14-96
!
! This is a library to handle perception of the senses of Hearing, Smell, Touch
! and Taste. (I figured sight is pretty well handled by the library.)
! Instalation is fairly simple; This file should be included before Grammar,
! and the following lines shoudl appear before Verblib:
!
! Replace TouchSub;
! Replace ListenSub;
! Replace TastSub;
! Replace SmellSub;
!
! The following lines should be added to the LibraryMessages:
! (These are rerally optional, without them, attempts to smell a visible but
! unsmellable object, for example, will yield the library default.)
!
! Smell: if (lm_n==4) print_ret "You can't smell ", (the) noun, " from here.";
! Listen: if (lm_n==4) print_ret "You can't hear ", (the) noun, " from here.";
! Taste: if (lm_n==4) print_ret "You can't taste ", (the) noun, " from here.";
! Touch: if (lm_n==4) print_ret "You can't touch ", (the) noun, " from here.";
!
! This library uses four attributes, which are sense-versions of the library's
! "Transparent" attribute. It also uses six properties (sorry), one for each
! sense, and two to handle sense "muting". One Global variable (Sensedepth)
! is used. It could have probably been done by using return values, but this
! was was more convenient for me.
!
! To use this library, give each object a string or routine for the properties
! "feel" "scent" "sound" and "taste". Objects without these will return
! the usual Library message. If an object's description depends on how deeply
! it is buried, a routine could check the sensedepth variable. Sensedepth is
! the degree of separation between the player and the object, an object in the
! room with the player has a sensedepth of 0. For example, a radio's sound
! routine could print "You hear some classical music" at a sensedepth of 0,
! and "You hear some muted music" at a sensedepth of 3.
! MaxSenseDepth is the deepest something can be "burried" while the parser
! still detects it. An object with a sensedepth greater than the MaxSenseDepth
! will not be noticed. This is important mostly for recursive senses, so that
! you don't get an anomalty like "Within the box you hear nothing unexpected"
!
! Smell and Listen recurse automatically; listening to an object will also
! listen to its contents, provided they are audible. The RecurseSense routine
! is provided to handle sense recursing.
!
! MaxSenseDepth has a default of 5, but can also be a routine, which checks
! the action varable, thus a perfumed radio (?) might only be smellable at
! a depth of 2, but could be heard as deep as 6.
!
! The Opacity of a container is its resistance to sensory transmittion.
! the default opacity is 1, but can be a routine as well. Opacity affects
! sensedepth: A radio in a box of opacity 2, which is inside a box of
! opacity 1 has a sensedepth of 3. Sensedepth recurses down the object
! tree, but not up, except to the parent of the player.
! Open containers do not affect sensedepth
!
! Because of the inclusion location, the player can not refer to an object
! that is not in normal scope. This is fairly logical, by my reconing, but
! I've made it easy if you want to add the ability to listen to the
! invisible radio: Add these lines AFTER Grammar:
!
! Extend "touch" * scope=TouchScope ->Touch;
! Extend "smell" * scope=SmellScope ->Smell;
! Extend "listen" * scope=HearScope ->Listen;
! Extend "taste" * scope=TasteScope ->Taste;
!
! There are two oddities I should mention; Unlike the other senses, containers
! are by default trasnsparent to sound. Give them soundproof to reverse this.
! Also, an object that is touchthru or tastethru is also smellthru, as I feel
! this is reasonably close to the way the world works. If you don't like this,
! have opacity return some huge number for action==##Smell.
!
Attribute smellthru; !Transparent to smell
Attribute touchthru; !Transparent to touch eg. has holes in it
Attribute tastethru; !Transparent to taste
Attribute soundproof; !Opaque to sound
property feel; !Response to "Touch" or routine to print one
property scent; !Same for smell
property sound; !Same for listen
property taste; !Same for taste
!These next two can also be properties which return a number
property opacity 1; !The amount that it obscures whatever's inside it
property MaxSenseDepth 5; !The maximum opacity at which it can be observed
Global sensedepth; !The sum of the opacities of the objects between the
!player and the thing (s)he is examining
! First, a routine to check whether or not the object can be sensed in the
! needed way
! InSenseScope(thing,Object,Reason) Determines whether Object is in scope of
! Thing by the sense Reason
! In order for sensedepth to work right, I needed two routines, one to rezero
! sensedepth, and a recursing one to measure it. DO NOT call SenseScope
! directly, use InSenseScope instead
[ SenseScope thing obj reason o flag i;
o = parent(obj);
i = parent(thing);
if (o==thing) rtrue;
if (IndirectlyContains(i,obj)==0 && i~=obj) rfalse;
! (Just in case a call is made to something that
! isn't in the room with the player)
if (o==i or thing) rtrue;
if (i==o or thing) rtrue;
if (o hasnt open)
sensedepth=sensedepth+ValueOrRun(o,opacity);
flag = 0;
switch(reason)
{ ##Touch: if (o has open || o has touchthru) flag=1;
##Smell: if (o has open || o has touchthru || o has smellthru || o has tastethru)
flag=1;
##Taste: if (o has open || o has tastethru) flag=1;
##Listen: if (o has open || o hasnt soundproof) flag=1;
};
if (flag==1) return SenseScope(thing,o,reason);
rfalse;
];
! RecurseSense(obj,sense) recurses through the tree from obj, printing their
! sense response, if they are in sensescope.
[ RecurseSense obj sense o i;
if (parser_trace>=3) print "[Recursing over the ", (name) obj, "]^";
if (ZRegion(obj.sense)==2 or 3 && InSenseScope(player,obj,action)==1
{PrintOrRun(obj,sense); i=1;};
objectloop (o in obj)
{if (RecurseSense(o,sense)==1) i=1;};
if (i~=0) rtrue;
rfalse;
];
! The new Routines for Touch,Smell,Taste, and Listen
[ TouchSub;
if (InSenseScope(player,noun,##Touch)==0) return L__M(##Touch,4);
if (ZRegion(noun.feel)==2 or 3) { PrintOrRun(noun,feel); rtrue;};
if (noun==player) return L__M(##Touch,3);
if (noun has animate) return L__M(##Touch,1);
L__M(##Touch,2); ];
[ SmellSub;
if (noun==0) <<Smell location>>;
if (InSenseScope(player,noun,##Smell)==0) return L__M(##Smell,4);
if (RecurseSense(noun,scent)==1) rtrue;
L__M(##Smell);
];
[ ListenSub;
if (noun==0) <<Listen location>>;
if (InSenseScope(player,noun,##Listen)==0) return L__M(##Listen,4);
if (RecurseSense(noun,sound)==1) rtrue;
L__M(##Listen);
];
[ TasteSub;
if (InSenseScope(player,noun,##Taste)==0) return L__M(##Taste,4);
if (ZRegion(noun.taste)==2 or 3) { PrintOrRun(noun,taste); rtrue;};
L__M(##Taste); ];
! Scope-Checking routines in case you want to extend verb grammar
[ TouchScope i;
if (scope_stage==1) rfalse;
if (scope_stage==2) { for(i=selfobj+1:i<=top_object:i++)
if (InSenseScope(player,i,##Touch)==1) PlaceInScope(i);};
];
[ SmellScope i;
if (scope_stage==1) rfalse;
if (scope_stage==2) { for(i=selfobj+1:i<=top_object:i++)
if (InSenseScope(player,i,##Smell)==1) PlaceInScope(i);};
];
[ HearScope i;
if (scope_stage==1) rfalse;
if (scope_stage==2) { for(i=selfobj+1:i<=top_object:i++)
if (InSenseScope(player,i,##Listen)==1) PlaceInScope(i);};
];
[ TasteScope i;
if (scope_stage==1) rfalse;
if (scope_stage==2) { for(i=selfobj+1:i<=top_object:i++)
if (InSenseScope(player,i,##Taste)==1) PlaceInScope(i);};
];