!----------------------------------------------------------------------------
!  Dirsmap.h  version 2.10                                            2/22/99
!  Marnie Parker   aka Doe aka FemaleDeer                   doeadeer3@aol.com
!----------------------------------------------------------------------------

! 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 <sirius2@iname.com>) 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;


