! -----------------------------------------------------
! goto.h
!
! (c) 1999 by Toni Arnold, Zurich
!
! Serial Number 990721
!
! Implements the verb "go to <room name>".
! It performs a breath-first-search on the map of the 
! game and uses the nearest possible way.
! -----------------------------------------------------
! Source URL:
! http://www.copyriot.com/tarnold/goto.html 
! -----------------------------------------------------
!
! Setting up goto.h
! -----------------
! Because goto.h contains a global variable
! and a common property it has to be included
! at the beginning of the game source.
!
! The grammar extension of the verb 'go'
! (at the end of this description) has
! to be copied, pasted and uncommented at
! the end of the game source.
!
! The only point which really has to be considered of
! are room direction routines: they must not produce
! side effects during the search of the way.
! For that reason side effects must check the 
! global variable not_in_goto to be true before
! doing some side effects. Otherwise it must only
! return the target room.
!
!
! Example room (out of advent.inf)
! --------------------------------
!
!Object In_Hall_Of_Mists "In Hall of Mists" 
!  with goto_steps 0,           ! ----> room <----    # this is added 
!   name  "hall" "in" "mists" "of",                    # this is added 
!   ... 
!       description 
!               "You are at one end of a vast hall stretching, 
!               .... 
!               Rough stone steps lead up the dome.", 
!       s_to In_Nugget_Of_Gold_Room, 
!       w_to On_East_Bank_Of_Fissure, 
!       d_to In_Hall_Of_Mt_King, 
!       n_to In_Hall_Of_Mt_King, 
!       u_to 
!       [;  if (not_in_goto) { ! # manually addet in the source to omit side effects during goto search 
!             if (large_gold_nugget in player) 
!               "The dome is unclimbable."; 
!           } 
!           return At_Top_Of_Small_Pit; 
!
!       ]; 
!
!
! The perl script mk_room_name.pl is provided for 
! automatically adding room names to an existing game.
! For details see its html-documentation goto.html
! and the documentation in the script itself.
! -----------------------------------------------------

System_file;


! ----------------------------------------
! The grammar extension
! cut it out, uncomment it and copy it 
! to the end of your game file
! ----------------------------------------

!Extend 'geh' first
!  * 'zu'	         scope=scope_room	-> go_to
!  * 'zu' 'dem'/'der'    scope=scope_room	-> go_to;



Property goto_steps;	
Global not_in_goto = true;	! flag for direction routines


! -------------------
! definition of the
! maximum way length
! -------------------

Constant max_goto_way_length = 100;
Array goto_way --> max_goto_way_length;


! ------------------------------
! the main go_to verb
! --------------------
! noun contains a room_name
! ------------------------------

[goto_destination pseudoroom;		! computes the real destination of door objects
 do {
   if (metaclass(pseudoroom) == string) rfalse;
   if (metaclass(pseudoroom) == routine) pseudoroom = pseudoroom.call();
   if (pseudoroom provides door_to)	! if the room is provided by the door object
      pseudoroom = pseudoroom.door_to;	! take this room as target
 } until ((pseudoroom == 0) || (pseudoroom == 1) || (metaclass(pseudoroom) == object));
 return pseudoroom;	! ^ some routine could return true or false (e.g. In_Alcove in advent.inf)
];


!--------------------
! the main goto_verb
! -------------------

[go_toSub save_loc goal_room room next_room next_room2 active_number x obj dir i;

  not_in_goto = false;		! flag for no side effects in room routines

  goal_room = noun;		! name of the target room

  active_number = 1;		! init step mark for active room (0 means inactive)

  room = location;
  save_loc = location;		! needed to save the current location for doors

  if (room provides goto_steps) {	! darkness object has none
    room.goto_steps = 1;	        ! mark it as starting point
  }

  
  do {							! do -------------------------
    if (active_number > (max_goto_way_length+1)) {	! way too long to be stored
      goto_message(0);	 
      rtrue;
    }

    x = false;			! becomes true if at least one inactive neighbour room is found

    objectloop (room provides goto_steps) {	! go through every room in the game

      if (room.goto_steps == active_number) {	! if current room is a currently active room

        if (room == goal_room) jump Found_Goal; ! if it is found OK.

        location = room;			! for door objects to compute correctly

        objectloop (obj in compass) {		! else loop through all directions
           dir = obj.door_dir;
           if (room provides dir) {		! if current direction is provided
             next_room = goto_destination(room.dir);

             if (next_room provides goto_steps) {		! next_room could be a routine, ignore those
               if ((next_room has visited && next_room.goto_steps == 0)) {  ! if neighbour is not yet searched
                 next_room.goto_steps = active_number+1;	! it becomes active in the next turn
                 x = true;				        ! at least one inactive neighbour room was found
               }
             }

           }
        } ! end compass loop

      } ! end active room condition

    }   ! end of objectloop for all rooms for current step

    active_number++;		! search rooms for the next step

  } until (x == false);				! until no room left for search	----------------


  goto_message(2);		! which means that the target room is not reachable from location
  location = save_loc;		! restore location and quit
  rtrue;
 

  ! --------- room is found and in real_room -------
  !  room_steps are set up with steps that are
  !  needed to get there
  .Found_Goal;
  
  if (active_number == 1) {	! if no step has to be made
    goto_message(1);		! which means that target room equals current room
    location = save_loc;	! restore location
    rtrue;
  }

  ! else go backwards to the original room
  ! room contains the current destination room

  x = active_number - 1;                ! 'x' is not used no more, so it becomes for-next border
                         		! active_number is step of goal room
  for (i=0: i<x: i++) {
    active_number--;			! room with step - 1

    objectloop (next_room provides goto_steps) {	! loops through all rooms
      if(next_room.goto_steps == active_number) {	! if it's a room from where current room can be reached

        location = next_room;				! because some (door) routines need it
        objectloop(obj in compass) {
          dir = obj.door_dir;
          if (next_room provides dir) 	{	 	! next_room is a room with step = (step of room) - 1

            next_room2 = goto_destination(next_room.dir); ! neighbours backwards of current room

            if  (next_room2 == room) {     		! if it's the room before
              goto_way --> i = obj;			! obj2 is the direction to take

              room = next_room;	                	! new target room (for backwards going)
 
              jump next_i;
            }

          }		! ---- room's which provide dir

        }		! ---- compass loop of room

      }		! ---- if condition i-1
    }		! ---- objectloop for all rooms

    .next_i;	! just an abbreviation
  }  ! ---- backward loop for all step distances i



  ! ------- now walk the given way ---------

  location = save_loc;		! restore location
  not_in_goto = true;		! activate side effects

  for (i=(x-1): i>=0: i--) {
    obj = location;
    
    <Go goto_way-->i >;		! perform the go action
    InformLibrary.end_turn_sequence();  ! and adjust the turns and the time
    
    if (location == obj) {	! if go had no effect for some reason
       goto_message(3);
       rtrue;
    }
  }


];    ! ------------ end of main go verb ------------






! ==================== verb extension =====================


! ------- definition of scope of the new verb --------------

[scope_room room;
  if (scope_stage == 1) rfalse;
  if (scope_stage == 2) {
    objectloop (room provides goto_steps) {
      if (room has visited) {
        room.goto_steps = 0;	! reset room step counter (= mark it as inactive) 
        PlaceInScope(room);
      }
    }
  rtrue;
  }
  goto_message(4);
  rtrue;
];


! ------------- the library messages ------------
! goto is always finished when a message occurs

[goto_message n;
  switch(n) {
   0: "Der Weg dorthin ist zu weit. Versuch's doch mal mit einer k@:urzeren Etappe!";
   1: "Aber du bist doch schon da!";
   2: "Der Weg zu deinem Ziel ist irgendwie zu kompliziert.";
   3: "Da war etwas Unerwartetes in deinem Weg, das dich am
       Weiterkommen hindert.";
   4: "Ich verstehe nicht, wohin du gehen willst.";
  }
 not_in_goto = true;	! reset flag before finishing
 rtrue;
];



! ----------------------------------------------------------




