!-------------------------------------------------------------------------
! maze.inf -- A component of the Inform Port of Ditch Day Drifter
!
! This file contains the source code for the Behavior Lab Maze.
! -------------------------------------------------------------------------
! -------------------------------------------------------------------------
!
! -- Table of Contents --
!
! MAZE (6)
!   Outside Maze (6.1)
!     maze equipment (6.1.1)
!     maze view (6.1.2)
!
!  exits property (L)
!  MazeRoom class (M)
!
!   Maze Room 1 (6.2)
!   Maze Room 2 through 35 (6.3)
!   Start of Maze (6.4)
!     behavior door north (6.4.1)
!
! -------------------------------------------------------------------------

! (6) MAZE

! (6.1) Outside Maze

Object OutsideMaze "Outside Maze"
 has light
 with 
  description [; 
     print "You are in a small room, with exits north and south. The
       passage to the north has a small sign reading, ~Behavior Lab Maze~.
       The room is filled with strange equipment, which you surmise is
       connected in some way to the maze. ";
     if (mazeequip has general) print "The equipment is buzzing loudly.
       Standing near it makes you feel vaguely dizzy. ";
     if (self hasnt visited) {
       print "^^You sigh in exasperation as you realize that you have
         reached the obligatory Adventure Game Maze, and ";
       if (MazeView has visited) print "you wish that this were a graphical
         adventure, so your trip to the maze viewing room had resulted in a
         map you could refer to now. Fortunately, you do recall noting that
         the passages in the maze all lead east-west or north-south. ";
       else print "wonder what this maze's unique twist will be. Surely, it
         won't just be a boring old labyrinth... ";
     }
     new_line;
     rtrue;
  ],
  before [; 
     Go:
       if (noun == in_obj) <<Go n_obj>>; 
  ],
  s_to Tunnel13, n_to Maze1;

! (6.1.1) maze equipment

! -------------------------------------------------------------------------
! The control panel in the steam tunnels controls the equipment. The
! equipment's state determines whether or not the maze exits will be
! randomized. This maze is quite easy once you turn off the equipment, and
! nearly impossible before that.
! -------------------------------------------------------------------------
Object -> mazeequip "equipment"
 has scenery general ! if it is on
 with 
  article "some",
  name 'equipment' 'coil' 'coils' 'pipe' 'pipes' 'wire' 'wires' 'electric'
       'electrical' 'tangled' 'web',
  description [; 
     print "The equipment resembles some of the particle accelerators that
       you have seen. It has several huge electric coils, all arranged
       around a series of foot-diameter pipes. A tangled web of enormous
       wires connects various parts of the equipment together and other
       wires feed it power. ";
     if (self has general) "The equipment is buzzing loudly. Standing near
       it makes you feel vaguely dizzy.";
     new_line; rtrue;
  ],
  react_before [;
    Listen: if (noun == 0) <<Listen self>>;
  ],
  before [; 
     ! Clever players will try turning the equipment on and
     ! off from here.
     SwitchOff: 
       print "There seems to be no way to do that. ";
       if (self hasnt general) print "Besides, it doesn't even appear to be 
         on.";
       new_line; rtrue;
     SwitchOn:
       print "There seems to be no way to do that. ";
       if (self has general) print "Besides, it appears to be already on.";
       new_line; rtrue;
     SwitchVague:
       "There seems to be no way to do that.";
     ! I want to capture a few other things the player might try.
     Turn:
       "There don't seem to be any dials.";
     Push:
       "There are no buttons visible in the tangled web of wires and pipes.";
     Pull:
       "There are no levers to pull.";
     Attack:
       "The equipment proves highly resilient.";
     Listen:
       if (self has general) 
         "The equipment is making a loud buzzing sound.";
  ],
;

! (6.1.2) maze view

! To allow players to type "enter the behavior lab maze"
Object maze_view "maze"
 has static concealed enterable
 with 
  parse_name [ 
    wd adj_count noun_count;

    wd=NextWord();
    while (wd == 'behavior' or 'lab') { adj_count++; wd=NextWord(); }
    while (wd == 'maze' or 'labyrinth') { noun_count++; wd=NextWord(); }
    if (noun_count) return adj_count+noun_count;
    else return 0;
  ],
  description "You can't see much from here.", 
  before [;
    Enter: <<GoIn>>;
    Examine: rfalse;
    default: "The view of the maze isn't important.";
  ],
  found_in OutsideMaze BehaviorLab, 
;

! (L) exits property

! Using an alias for number will hopefully make the code a bit more
! readable.
Property exits alias number;

! (M) MazeRoom class

! -------------------------------------------------------------------------
! Each room in the maze will be of class MazeRoom.
! 
! In a maze room, all travel will be randomized until the equipment is
! turned off. 
! 
! The exits property of each room will hold an array of exits from the
! room. Each of the four elements represents a direction, as shown by the
! following table.
! 
!   element  direction
!      0       north
!      1       south
!      2       east
!      3       west
!
! Property arrays are a little tricky in Inform, since they require a
! slightly different syntax from global arrays. Property arrays are always
! word arrays (2 bytes per element in z-code, 4 bytes per element in
! glulx). You access them with the syntax:
! 
!   object.&property-->n
!
! Where n is 0 to 1 minus the number of elements in the array. ".&" is
! really just an operator, which returns the address of the start of a
! property array.
! 
! The code below obviates some of the syntax by assigning the address of
! the array to a variable, exits_entry.
!
! You can find the number of elements in a property array using the .#
! operator:
!
!   object.#property
!
! evaluates to the number of elements in the array.
! -------------------------------------------------------------------------
Class MazeRoom
 has light
 with 
  short_name [;
    if (mazeequip has general) print "Lost in the Maze";
    else print "In the Maze";
    rtrue;
  ],
  ! this assures room descriptions will be printed every turn while the
  ! equipment is on. We don't want "verbose" and "brief" mode giving away
  ! too much.
  each_turn [; if (mazeequip has general) give self ~visited; ],
  description [ 
    i exits_entry count total_exits;  

    ! Let the player know that something fishy is going on...
    if (mazeequip has general) "You can't quite seem to get your bearings.
      There are some passages leading away, but you can't quite tell how
      many or in which direction they lead.";
    ! Otherwise, be incredibly helpful by listing the available exits from
    ! the room (the algorithm for this cribbed from the TADS version).
    else {
      print "You are in a room in the maze; they all look alike. You can go ";
      ! Obtain the address of the property array, exits.
      exits_entry=self.&exits;

      ! Loop through and count up the availlable exits. A non-zero indicates 
      ! an exit. We have to know how many exits there are so that 'and' and
      ! commas can be written sensibly, below. A 0 entry in the array
      ! indicates "no exit".
      for (i=0: i <= 3: i++)
        if (exits_entry-->i ~= 0) total_exits++;

      ! Loop through again and print out the available exits.
      for (i=0: i <= 3: i++ ) {
        if (exits_entry-->i ~= 0) {
          if (count > 0) {
            ! Two exits will have " and " placed between them.
            if (total_exits == 2) print " and ";
            ! If there are more than two exit, the last exit will have 
            ! ", and " placed before it.
            else if (total_exits == (count + 1)) print ", and ";
            else print ", ";
          }
          count++;
          switch (i) {
            0: print "north";
            1: print "south";
            2: print "east";
            3: print "west";
          }
        }
      }
      ! Print a period and return true.
      ".";
    }
  ],
  mazetravel [ index
    i destination exits_entry rvalue;

    exits_entry=self.&exits;
    if (mazeequip has general) {
      ! The directions are random.
      print "You can't figure out which direction is which; the more you 
        stumble about, the more the room seems to spin around. After a
        few steps, you're not sure if you've actually gone anywhere,
        since all these rooms look alike...^";

      ! keep trying random numbers until a valid exit is found.
      do {
        i=random(6)-1;
        destination=exits_entry-->i;
        if (destination == 0) rvalue=0;
        else if (i < 4) rvalue=destination;
        ! On a roll of 4 or 5, you secretly stay in same room.
        else rvalue=self;
      } until (rvalue ~= 0);
    }
    else {
      ! The directions are deterministic.
      ! The "magic number" -1 is used as a flag to indicate a direction you
      ! can't go.
      if (index == -1) rvalue=0;
      ! Otherwise the exit is between 0 and 3, and represents a
      ! direction.
      !   0=north
      !   1=south
      !   2=east
      !   3=west
      else rvalue=exits_entry-->index;
    }
    return rvalue;
  ],
  before [;
    Go:
      if (noun == in_obj) "You are already in the maze.";
    ! The library never actually generates a <<Go out_obj>> action. It uses
    ! the generic <<Exit>> action instead, which doesn't call <<Go>>.
    Exit: "If only it were that simple.";
  ],
  n_to [; return self.mazetravel(0); ],
  s_to [; return self.mazetravel(1); ],
  e_to [; return self.mazetravel(2); ],
  w_to [; return self.mazetravel(3); ],
  u_to [; return self.mazetravel(-1); ],
  d_to [; return self.mazetravel(-1); ],
  ne_to [; return self.mazetravel(-1); ],
  nw_to [; return self.mazetravel(-1); ],
  se_to [; return self.mazetravel(-1); ],
  sw_to [; return self.mazetravel(-1); ],
;

! (6.2) Maze Room 1

! -------------------------------------------------------------------------
! This room gives the quick thinking player a chance to prevent themselves
! from becoming hopelessly stuck in the random maze -- typing 'exit' 
! from the first room will always allow instant escape.
! -------------------------------------------------------------------------
MazeRoom Maze1 
 with
  before [; 
    Exit: 
      PlayerTo(OutsideMaze);
      rtrue;
  ],
  exits 0 OutsideMaze Maze2 0;

! (6.3) Maze Room 2 through Maze Room 35

! -------------------------------------------------------------------------
!                          north  south  east   west
! -------------------------------------------------------------------------
MazeRoom Maze2 with exits  Maze9  0      Maze3  Maze1;

MazeRoom Maze3 with exits  Maze8  0      Maze4  Maze2;

MazeRoom Maze4 with exits  0      0      Maze5  Maze3;

MazeRoom Maze5 with exits  Maze6  0      0      Maze4;

MazeRoom Maze6 with exits  0      Maze5  0      Maze7;

MazeRoom Maze7 with exits  Maze30 0      Maze9  Maze8;

MazeRoom Maze8 with exits  Maze29 Maze3  Maze7  0;

MazeRoom Maze9 with exits  0      Maze2  0      Maze10;

MazeRoom Maze10 with exits 0      0      Maze9  Maze11;

MazeRoom Maze11 with exits 0      Maze35 Maze10 Maze12;

MazeRoom Maze12 with exits 0      0      Maze11 0;

MazeRoom Maze13 with exits Maze24 Maze18 0      0;

MazeRoom Maze14 with exits 0      Maze17 0      Maze15;

MazeRoom Maze15 with exits 0      Maze16 Maze14 0;

MazeRoom Maze16 with exits Maze15 Maze23 Maze17 0;

MazeRoom Maze17 with exits Maze14 Maze22 Maze18 Maze16;

MazeRoom Maze18 with exits Maze13 Maze21 0      Maze17;

MazeRoom Maze19 with exits 0      Maze20 Maze35 0;

MazeRoom Maze20 with exits Maze19 0      0      Maze21;

MazeRoom Maze21 with exits Maze18 0      Maze20 0;

MazeRoom Maze22 with exits Maze17 0      0      0;

MazeRoom Maze23 with exits Maze16 0      0      0;

MazeRoom Maze24 with exits 0      Maze13 Maze25 0;

MazeRoom Maze25 with exits Maze33 0      Maze26 Maze24;

MazeRoom Maze26 with exits Maze32 0      0      Maze25;

MazeRoom Maze27 with exits Maze31 0      0      0;

MazeRoom Maze28 with exits 0      0      Maze29 0;

MazeRoom Maze29 with exits 0      Maze8  Maze30 Maze28;

MazeRoom Maze30 with exits 0      Maze7  0      Maze29;

MazeRoom Maze31 with exits 0      Maze27 0      Maze32;

MazeRoom Maze32 with exits 0      Maze26 Maze31 0;

MazeRoom Maze33 with exits 0      Maze25 0      Maze34;

MazeRoom Maze34 with exits 0      0      Maze33 MazeStart;

MazeRoom Maze35 with exits Maze11 0      0      Maze19;

! (6.4) Start of Maze

! You end up solving the maze "backwards" in Ditch Day, going from the exit
! to the entrance. Nice gimmick, eh?
Object MazeStart "Start of Maze"
 has light
 with 
  description "You are at the start of the maze. A passage into the maze is
    to the east, and a heavy one-way door marked ~Exit~ is to the south.",
  before [;
    Exit: <<Go s_obj>>;
  ],
  e_to Maze34, s_to behavior_door_n,
;

! (6.4.1) behavior door north

Object behavior_door_n "door" MazeStart
 has door openable scenery
 with
  name "door" "behavior",
  description [;
    print "The door is ";
    if (self has open) "open.";
    else "closed.";
  ],
  ! Objects with a timer must supply a time_left property and must not use
  ! it for anything.
  time_left 0,
  time_out [;
    give self ~open;
    "^The door swings shut.";
  ],
  after [;
    Open: StartTimer(self, 1);
  ],
  door_dir s_to, door_to BehaviorLab,
;