!----------------------------------------------------------------------------
!  Dirsmap.h  version 2.10                                            2/22/99
!  Marnie Parker   aka Doe aka FemaleDeer                   [email protected]
!----------------------------------------------------------------------------

! Version 2 replaces the extended ASCII codes that will not work with
! all interpreters, with simple letter characters.

! Version 2.1 offers a choice of map styles for the author to use (and also
! sets the map style to a fixed font format). The player can then toggle
! between the map style (chosen by the author) and the sentence style.

!----------------------------------------------------------------------------

! This is a hack/upgrade of a routine shared by Dragonslayer on Wed 17,
! Sept 97, in raif (rec.arts.int.fiction). I liked his routine very much, but
! found it a bit inflexible for what I wanted, so I made several changes.
! With Dragonslayer's (Josh Bonner <[email protected]>) permission, I am
! contributing the changed routine to the if archive.

! Adds a directions command to Inform. Depending on the current dirs_style,
! toggleable by the player within the game, available exits are shown either
! with a map or in a sentence.

! Map style:
!>exits      use_char = 0 (default)
!
!    \ n /  u in
!   w  o  e
!    / s \  d out

!            use_char = 1
!
!    \ | /  | in
!   -- o --
!    / | \  | out

! These map styles are offered as guide lines, but are easily customizable.

! Sentence style:
!>exits
!  "You can go to the north, south, southeast and southwest."

! Default style is the map style.

! Omits non-existent exits.

! Include this file after parser.h and be sure to include mention of the
! new commands (see below) in your help screens, so the player knows of them.

!----------------------------------------------------------------------------
! Directions for Usage of the New Property, exclude_dirs.
!
! Following are the major changes I made to Dragonslayer's original routine.
!----------------------------------------------------------------------------

! Omits exits that return a string, such as:
!
! s_to "The wall is in the way.";
!
! Includes exits that use a routine, such as:
!
! s_to
! [; if (boulder hasnt general)
!       "The cave entrance is blocked by the boulder.";
!    return outside_cave;
! ];

! Unless that location's property, exclude_dirs, lists that exit as an exit
! to be excluded.

! The new property, exclude_dirs, is provided so the author can hide exits
! from the player that they want hidden (hidden from the exits command) until
! the appropriate time. Such as a hidden door, a boulder in front of cave
! entrance, etc. All such hidden exits are presumed to use routines, so
! exclude_dirs is only checked when the direction uses a routine.

! The reason the routine isn't "run" to determine if the routine would return
! a string or valid exit is because if it is "run" when it contains a string
! (see above), the string will be printed when it tested, "The cave entrance
! is blocked". This sort of behavior would be undesirable, so direction
! routines are automatically included unless specifically excluded.

! Some of the following explanation is provided for Inform newbies or
! those still unfamiliar with array properties.

! So if the author doesn't want a direction included in the exits command
! until later:

! Object Cave "Cave"
! with exclude_dirs s_obj,
! s_to
! [; if (boulder hasnt general)
!       "The cave entrance is blocked by the boulder.";
!    return outside_cave;
! ];

! Note that the exit excluded must be of the "obj" type of direction instead
! the "to" type (actual direction instead of direction to). Then somewhere in
! the code, once the boulder is moved, the Cave's exclude_dirs property would
! be set to 0.

! Object -> boulder "boulder"
! with name "boulder",
! before
! [; Pull, Push : if (boulder has general)
!                    "No point in moving it back in front of the entrance.";
!                 give boulder general;
!                 Cave.exclude_dirs = 0;
!                 "You move the boulder out of the way.";
! ];

! Like, found_in, exclude_dirs can also be an array or a routine, but if a
! routine, it shouldn't include a string (for the same reason as above, testing
! it for the exits command will print the string). As an array, exclude_dirs
! can also be set to 0 when the condition that unhides the direction is met.

! An array property is accessed with a pointer to the element of the array,
! the first element of the array is 0, the second 1, etc. Also note when
! using an array property that it must start with the same number of total
! elements that it will end up with (there is no dynamic allocation).

! Object Cave "Cave"
! with exclude_dirs s_obj 0,
! s_to
! [; if (boulder hasnt general)
!       "The right tunnel entrance is blocked by the boulder.";
!    return r_tunnel;
! ],
! n_to
! [; if (boulder has general)
!       "Now the left tunnel entrance is blocked by the boulder.";
!    return l_tunnel;
! ];

! Object -> boulder "boulder"
! with name "boulder",
! before
! [; Pull, Push :
!       if (boulder hasnt general)
!       {  give boulder general;
!          Cave.&exclude_dirs-->0 = 0;
!          Cave.&exclude_dirs-->1 = n_obj;
!          "You move the boulder out of the way. A right tunnel is revealed.";
!       }
!       give boulder ~general;
!       Cave.&exclude_dirs-->0 = s_obj;
!       Cave.&exclude_dirs-->1 = 0;
!       "You move the boulder out of the way. The left tunnel is revealed again.";
! ];

! The above is to demonstrate how to use exclude_dirs as an array property,
! but better coding in this specific instance would be an exclude_dirs routine:

! Object Cave "Cave"
! with exclude_dirs
! [; if (boulder hasnt general) return s_obj; return n_obj; ],
! s_to
! [; if (boulder hasnt general)
!       "The right tunnel entrance is blocked by the boulder.";
!    return r_tunnel;
! ],
! n_to
! [; if (boulder has general)
!       "Now the left tunnel entrance is blocked by the boulder.";
!    return l_tunnel;
! ];

! Object -> boulder "boulder"
! with name "boulder",
! before
! [; Pull, Push :
!       if (boulder hasnt general)
!       {  give boulder general;
!          "You move the boulder out of the way. A right tunnel is revealed.";
!       }
!       give boulder ~general;
!       "You move the boulder out of the way. The left tunnel is revealed again.";
! ];

! exclude_dirs need not be used at all, it is just included to provide the
! author with the greatest flexibility for the exits command.

! Note:  Dirs assigns the workflag to the directions within the actual
! compass object itself (english.h), but this should create no problems as the
! Inform library does not check the compass directions for a workflag. The
! workflag is assigned in order to use WriteListFrom for the sentence style.

!----------------------------------------------------------------------------
! Globals and the Dirs Routine
!----------------------------------------------------------------------------

Global use_char = 0;   ! ***** Changeable. The game author sets the desired
                      ! map style before compiling. (Set to 0 or 1). ******

Global dirs_style = 0; ! In the game, the player can set/toggle at the prompt
                      ! and/or in a menu how they want exits displayed, with a
                      ! map or in a sentence.

! This property need not be global, it can be local (commented out).

Property exclude_dirs 0;

[ DirsSub i j k l m n o p t;

! If you prefer to have no directions "visible" in the dark, change these
! lines to something like:
! if (location == thedark) "It is too dark to see your way.";
! else l = location.

 if (location == thedark) l = real_location;
 else l = location;

 objectloop(i in compass)
 { if (l provides i.door_dir)
   {  j = 0;
      p = l.(i.door_dir);
      if (ZRegion(p) ~= 0 or 3) j = 1;
      if ((ZRegion(p) == 2) && (l provides exclude_dirs))
      {  if (ZRegion(l.&exclude_dirs-->0) == 2)
         {  o = l.exclude_dirs();
            if (o == i) j = 0;
         }
         else
         {  m = l.#exclude_dirs;
            for (n = 0: n < (m/2): n++)
            { o = l.&exclude_dirs-->n;
              if (o == i) j = 0;
            }
         }
      }
      if (j ~= 0) { k ++; give i workflag; }
      else give i ~workflag;
   }
   else give i ~workflag;
 }
 if (dirs_style == 0)
 { font off;
   print "^    ";
   if (nw_obj has workflag) print " @@92 ";
   else print "   ";
   if (n_obj has workflag)
   { if (use_char == 0) print "n "; else print "| "; }
   else print "  ";
   if (ne_obj has workflag) print "/ ";
   else print "  ";
   if (u_obj has workflag)
   { if (use_char == 0) print " u"; else print " |"; }
   else print "  ";
   if (in_obj has workflag) print " in";
   print "^    ";
   if (w_obj has workflag)
   { if (use_char == 0) print "w  "; else print "-- "; }
   else print "   ";
   print "o ";
   if (e_obj has workflag)
   { if (use_char == 0) print " e "; else print "-- "; }
   else print "   ";
   print "^    ";
   if (sw_obj has workflag) print " / ";
   else print "   ";
   if (s_obj has workflag)
   { if (use_char == 0) print "s "; else print "| "; }
   else print "  ";
   if (se_obj has workflag) print "@@92 ";
   else print "  ";
   if (d_obj has workflag)
   { if (use_char == 0) print " d"; else print " |"; }
   else print "  ";
   if (out_obj has workflag) print " out";
   print "^";
   font on;
   rtrue;
 }
 else
 { if (k == 0) "There are no obvious exits here.";
   t = NOARTICLE_BIT + ENGLISH_BIT + PARTINV_BIT + RECURSE_BIT + WORKFLAG_BIT;
   print "You can go to the ";
   WriteListFrom(child(compass), t);
   ".";
 }
];

!----------------------------------------------------------------------------
! Changes the Dirs Style
!----------------------------------------------------------------------------

! These routines could be separate AND/OR the dirs_style could be toggled in
! a help menu in addition to or instead of at the prompt. Using L. Ross
! Raszewski's AltMenu & DoMenu, here is one way to toggle the dirs_style:
!
! SwitchOption -> -> maponoff
!        with label [; print "Exits Display   ";
!                      if (dirs_style == 0) style reverse; print "MAP";
!                      style roman; print "   ";
!                      if (dirs_style == 1) style reverse; print "WORDS";
!                      style roman; ],
!       toggle [; if (dirs_style == 1) dirs_style = 0; else dirs_style = 1; ];


[ MapOnSub;
 dirs_style = 0;
 "[Available exits are now displayed with a map.]";
];

[ MapOffSub;
 dirs_style = 1;
 "[Available exits are now listed in a sentence.]";
];

!----------------------------------------------------------------------------
! Commands
!----------------------------------------------------------------------------

Verb meta 'exits' 'dirs' 'directions'
               *                                -> Dirs;
Verb meta 'list'
               * 'exits'                        -> Dirs
               * 'dirs'                         -> Dirs
               * 'directions'                   -> Dirs;
Verb meta 'map'
               * 'on'                           -> MapOn
               * 'off'                          -> MapOff;