#!/usr/local/bin/perl
#################################################################################
#
#  IIII  NN    NN  FFFFFFF OOOO   RRRRRRR   MM    MM    AAAA    PPPPPP
#   II   MM    NN  FF     OO  OO  RR    RR  MMM  MMM   AA  AA   PP   PP
#   II   NNN   NN  FF    OO    OO RR    RR  MMM  MMM  AA    AA  PP   PP
#   II   NN N  MM  FFFFF OO    OO RRRRRRR   MM MM MM  AAAAAAAA  PPPPPP
#   II   NN  NNNN  FF    OO    OO RR  RR    MM    MM  AA    AA  PP
#   II   NN    NN  FF     OO  OO  RR   RR   MM    MM  AA    AA  PP
#  IIII  NN    NN  FF      OOOO   RR    RR  MM    MM  AA    AA  PP
#
#
#               F L O A T   T H E   C A V E  . . .
#
#
# (c) 1998/1999 by Toni Arnold, Zurich
# ------------------------------------------------------------------------------
# Perl-Script that draws a map in ASCII-"graphics"
# out of an Inform source file
#
# Version 1.1b0
# Serial Number 990507
#
# Some information about perl can be found at:
# http://www.gnu.org/software/perl/perl.html
# ------------------------------------------------------------------------------
# Comments and bug reports to:
#  tarnold@cl.unizh.ch
#
# Copying is free as long as it is
#  - not commercial
#  - copied as a whole
# ------------------------------------------------------------------------------
#
# Call
# ----
#
# perl informap.pl infile [outfile] [flags]
#
# This creates a map with filename: filename.map.txt
# Have a look at that map with your favorite ASCII-Text-editor.
#     (be sure to switch word wrapping off!)
#
# outfile
# -------
# Some machines (eg. DOS) don't allow long filenames. For that reason
# the second argument is recognized as the output filename if it is
# not a flag. If there are multiple columns selected, the (necessary)
# numbers in the filename are added as extension to the outfile which
# makes it a file type. This not really good, but I found no other
# general solution.
#
# Flags 
# -----
#
# flags are recognized by a letter followed by =
# ignores the case of the flag letter and they can appear in any order
#
# n=[number]  e.g. N=15
# ----------
# number is the width of a single room NAME printed and defaults to 11
# only odd numbers are accepded, even numers are increased by 1
#
# c=[number]  e.g. C=80
# ----------
# number is the width of a single COLUMN to be printed out. Maps get often
# larger than the maximum width of a text on the printer. For printing them
# they are split if they are larger than the column width. The filenames 
# become then filename.map.001.txt filename.map.002.txt ....
#
# f=[on/off]  e.g. f=off
# ----------
# This flag indicates whether "Include"-FILEPATHS should be FOLLOWED
# or not. There are files defined which are ignored always. Edit
# @include_ignore = (...); below to add files to the ignore-list.
# Default is on.
#
# p=[hor/ver] e.g. p=ver
# -----------
# It is common style to program both a HORIZONTAL direction, e.g. w_to,
# and a VERTICAL direction, e.g. d_to, to the same room. In that case
# informap has to choose whether the horizontal direction has to be drawn
# (on the same floor) or the vertical one on a new floor (below in the
# example). Default is to PREFER horizontal - the flag can change this.
#
#
# Comment about the call in Windows
# ---------------------------------
# On Unix it is possible to call perl without "perl" by adjoining the
# perl binary path to the first line of the script. On Windows NT *.pl
# can be associated with perl, which works at least with the ActiveState
# distribution.
# ------------------------------------------------------------------------------
#
# Revision history
# ----------------
#
# V1.0   first release
# V1.1   before[go; n_obj: PlayerTo(Room,2)]; is now recognized
# 
# ------------------------------------------------------------------------------
#
# Known Bugs and lacks
# --------------------
#
# - Doors (door_dir) are not handled
# - out_to is not handled. This is really a problem e.g. in adventure.inf
#
# ------------------------------------------------------------------------------
#
# Example
# =======
#
# The following is a shortened inform file:
# -----------------------------------------
#
# Object Middle
#  n_to North
#  s_to south
#  w_to West
#  sw_to southwest
#  nw_to northwest
#
# Object Southwest
#  ne_to Middle
#  n_to West
#
# Object North
#  s_to middle
#  d_to cellar
#
# Object West
#  e_to Middle
#  n_to Northwest
#  s_to South
#
# Object Cellar
#  u_to North
#
# Object NorthWest
#  se_to South
#  s_to West
#
# Object South
#  nw_to Northwest
#  n_to Middle
#
#
# This is the map drawn by INFORMAP:
# ----------------------------------
#
#                     ______________          ______________
#                    /             /         /             /
#                   /  northwest  /         /    north    / 
#                  /___________|south|     /_____________/  
#                                                  |        
#                       /         ^             /  |        
#                      /           ^           /   |        
#                     /             ^         /    :        
#             ______________          ______________        
#            /             /         /             /        
#           /    west     / ------- /   middle    /.        
#          /___>south>___/         /_____________/          
#                               ___                         
#               ^           ___/        /          .        
#              ^        ___/           /                    
#             ^     ___/              /                     
#     ______________          ______________       .        
#    /             /     |northwe|         /                
#   /  southwest  /         /    south    /                 
#  /_____________/         /_____________/         .        
#                                                           
#                                                           
#                                                  .        
#                                                  :        
#                                                  |        
#                                                  |        
#                                             _____|________
#                                            /             /
#                                           /   cellar    / 
#                                          /_____________/  
#
#
# Legend
# ------
# - Names in squares are rooms
# - Connections in between ("lines") are compass directions
# - If a connection is drawn as >>> od ^^^ it is only in one direction
# - If a room cannot be connected with a line it is printed on the border
#   of the room it is attached to. It is written as |room| if it is bidirectional
#   and as >room> if it is only in one direction
#
# ------------------------------------------------------------------------------
# This file contains the whole commented source code. I suppose that it still
# contains inconsistencies and the like; I just made it work by hacking.
#
# Table of sections
# -----------------
#
# SECTION 1: GET COMMAND LINE
# SECTION 2: GET FILE(S) AND DECODE INPUT
# SECTION 3: BUILD LOGICAL MAP
# SECTION 4: BUILD LOGICAL DIRECTIONS
# SECTION 5: BUILD GRAPHICAL MAP
# SECTION 6: SAVE GRAPHICAL MAP
#
# For non-perl-users: the script has to be read as a script which is executed
# line per line from top to bottom. Subroutines (sub name { ) of course are
# skipped while passing them executing the script.
# Some parts (esp. sections 3 and 4) are extremely redundant. With Object
# oriented programming the space could possibly be reduced, but I was not
# able to use objects, so the code is old fashioned c-klone-style.
#################################################################################


# This Array contains "include"-files that shoud be ignored.
# It can be parts of the game that should not be "mapped"
# or - more important - library files containig rooms
# Case is ignored!

@include_ignore = ("Parser","VerbLib","Grammar",
                   "GermanG");			# language library



$outfile_suffix = ".map";		# change it if you like it different
$outfile_type = ".txt";



#######################
# Print title message #
#######################

print "\nINFORMAP  V1.1b0\n";
print "(c) 1998/1999 by Toni Arnold, Zurich\n\n";



####################### SECTION 1: GET COMMAND LINE ##########################


#####################################
# get the arguments
#####################################

# first argument = inform file
# $inform to draw a map from 
# -> open it and read content to
# @inform


$inform = $ARGV[0];
$outfile_name = $inform;	# can be overridden by explicite filename

if ((not defined($inform)) or ($inform =~ /\w=.*/)) {
  die "No input file specified!\nCall: perl informap.pl infile [outfile] [flags]\n";
}

# argument defaults
$room_width = 13;
$column_width = 99999;
$include_flag = "on";
$prefer_dir = "hor";


# facualtative more arguments
# n=13  width of the room Names (default = 11)
#        allows only odd numbers
# c=80  width of a column for printing
#       the columns get numbered from 000 to 999
#        (default = 99999 [+- infinite for screen])


for ($i=1;$i<=@ARGV;$i++) {			# number of arguments
  if (defined($ARGV[$i])) {
    $arg = $ARGV[$i];

    if (($i==1) &&	($arg ne "") &&		# second argument as possible filename
         ($arg !~ /\w=.*/)) {		        # matches everything except flags
      $outfile_name = $arg;			# take it as outfilename
      $outfile_suffix = "";			# no additional suffix and type
      $outfile_type = "";
      $arg = "";			# mark as done
    };


    if ($arg =~ /n=(\d+)/i) {		# --- N=23 ---
      $room_width = $1;			

      if ($room_width > 33) { 		# names in inform up to 32 chars
        $room_width = 33;
      };

      if ($room_width < 0) {		# if < 0 make it > 0
        $room_width = $room_width * -1;  # (not necessary no more)
      };

      if (($room_width % 2) == 0) {	# if even
        $room_width++;		# make it odd
      };
      $arg = "";			# mark as done
    };


    if ($arg =~ /c=(\d+)/i) {		# --- C=23 ---
      $column_width = $1;
      $arg = "";
    };


    if (lc($arg) eq "f=on") {		# --- F=ON ---
      $include_flag = "on";
      $arg = "";
    };
    if (lc($arg) eq "f=off") {		# --- F=OFF ---
      $include_flag = "off";
      $arg = "";
    };


    if (lc($arg) eq "p=hor") {		# --- P=HOR ---
      $prefer_dir = "hor";
      $arg = "";
    };
    if (lc($arg) eq "p=ver") {		# --- P=VER ---
      $prefer_dir = "ver";
      $arg = "";
    };


    if ($arg ne "") {		# !! die on invalid arguments !!
      die ("Invalid argument: $arg\n");
    };
  };    
};







#################### SECTION 2: GET FILE(S) AND DECODE INPUT ####################


#########################################
# Read Map-Relevant Data into Array
# of arrays of room
# --------------------------------------
# The array @room[n] contains afterwards
# for each room n an entry like below.
# Entry for room $x:
# @room($room_elements*$x)
#########################################

# @rooms[n] = 
$name = 0;
$n_to = 1;
$ne_to = 2;
$e_to = 3;
$se_to = 4;
$s_to = 5;
$sw_to = 6;
$w_to = 7;
$nw_to = 8;
$u_to = 9;
$d_to = 10;
$out_to = 11;
$in_to = 12;
#$door_dir = 13;

$room_elements = 14; # the number of elements to manually create
		  # multidimensional array 
 		  # (everything else didn't work)




# ------------------------------------------
# accommodate_new_room
# is called inside the input line loop
# every time when a direction is detected.
# if it's the first direction of the object,
# then the object is recognized as a room
# ------------------------------------------

sub accommodate_new_room {
  my($i);

  if ($room_detected eq "false") { # if it's not already recogn. as a room

    $room_number++; # increase room number to new room
    @room[$room_number*$room_elements] = $possible_room; # name of the room

    for ($i=1,$i<$room_elements,$i++) { # init direction strings
      @room[($room_number*$room_elements)+$i] = "";      # initial value
    };

    $room_detected = "true"; # mark current room as initialized
  };
}



# --------------------------------------------------
# is_valid_file(Filename)
# checks the Filename case insensitive against
# @include_ignore (at the beginning of the script)
# returns true if it is valid, else false
# --------------------------------------------------

sub is_valid_filename {
   my($file) = @_;
   my($a,$b,$i,$end,$out);

   $out = "true";		# init default value
   $a = lc($file);		# lower case filename
   $end = @include_ignore;

   for ($i=0;$i<=$end;$i++) {	# loop trough every skip filename
     $b = lc($include_ignore[$i]);
     if ($a eq $b) {
       $out = "false";
     };
   };

   $out;
}




# ---------------- input line loop --------------------
# @inform holds the current inform file
# graps the information from this file
# to handle include-statements it is a subroutine

sub input_line_loop {

  $line_number=0;
  $room_detected = "false";    # whether current object is a room
  $before_detected = "false";  # for before go: n_obj: PlayerTo...
  $go_detected = "false";      # the 'go:' itself
  $go_obj_detected = "";       # no go-obj yet detected



  while (<INFORMFILE>) {
   $line = $_;		 # $line contains the actual line


   if ($line !~ /^\s*!/) {	# skip commented lines

    $line =~ s/!.*//;	# remove comment at the end


  # pattern matching: recognize Include-Statements
    if ($include_flag eq "on") {
      if (($line =~ /include\s*"(.+)"/i) and
          (is_valid_filename($1) eq "true"))		{
         push (@file_stack,$1);
      };
    };

  # pattern matching: recognize object header (= new room)
    if ($line =~ /object\s+(\w+)/i ) {
                  # ^word "object" (/i = ignore case)
                        # ^word boundary
                             # ^name of the (possible) room object


      $possible_room = "\L$1\E";              # room name could be any object
      $possible_room =~ s/\Afalse\Z/false /;  # avoid name conflicts because
  #     FOR PERL false is equal to the string "false" (SHIT) -> add a space

      $room_detected = "false";    # so it is not detected as room up to now
      $before_detected = "false";  # and no before
      $go_detected = "false";      # and no go up to now
      $go_obj_detected = "";       # no go-obj yet detected
    };


  # === pattern matching: assign the explicite directions ===

    if ($line =~ /\bn_to\s+(\w+)/i ) {
      &accommodate_new_room;
      $r = "\L$1\E";
      $r =~ s/\Afalse\Z/false /; # avoid name conflicts
      @room[($room_number*$room_elements)+$n_to] = $r;
    };
   
    if ($line =~ /\bne_to\s+(\w+)/i ) {
      &accommodate_new_room;
      $r = "\L$1\E";
      $r =~ s/\Afalse\Z/false /; # avoid name conflicts
      @room[($room_number*$room_elements)+$ne_to] = $r;
    };

    if ($line =~ /\be_to\s+(\w+)/i ) {
      &accommodate_new_room;
      $r = "\L$1\E";
      $r =~ s/\Afalse\Z/false /; # avoid name conflicts
      @room[($room_number*$room_elements)+$e_to] = $r;
    };

    if ($line =~ /\bse_to\s+(\w+)/i ) {
      &accommodate_new_room;
      $r = "\L$1\E";
      $r =~ s/\Afalse\Z/false /; # avoid name conflicts
      @room[($room_number*$room_elements)+$se_to] = $r;
    };

    if ($line =~ /\bs_to\s+(\w+)/i ) {
      &accommodate_new_room;
      $r = "\L$1\E";
      $r =~ s/\Afalse\Z/false /; # avoid name conflicts
      @room[($room_number*$room_elements)+$s_to] = $r;
    };

    if ($line =~ /\bsw_to\s+(\w+)/i ) {
      &accommodate_new_room;
      $r = "\L$1\E";
      $r =~ s/\Afalse\Z/false /; # avoid name conflicts
      @room[($room_number*$room_elements)+$sw_to] = $r;
    };

    if ($line =~ /\bw_to\s+(\w+)/i ) {
      &accommodate_new_room;
      $r = "\L$1\E";
      $r =~ s/\Afalse\Z/false /; # avoid name conflicts
      @room[($room_number*$room_elements)+$w_to] = $r;
    };

    if ($line =~ /\bnw_to\s+(\w+)/i ) {
      &accommodate_new_room;
      $r = "\L$1\E";
      $r =~ s/\Afalse\Z/false /; # avoid name conflicts
      @room[($room_number*$room_elements)+$nw_to] = $r;
    };

    if ($line =~ /\bu_to\s+(\w+)/i ) {
      &accommodate_new_room;
      $r = "\L$1\E";
      $r =~ s/\Afalse\Z/false /; # avoid name conflicts
      @room[($room_number*$room_elements)+$u_to] = $r;
    };

    if ($line =~ /\bd_to\s+(\w+)/i ) {
      &accommodate_new_room;
      $r = "\L$1\E";
      $r =~ s/\Afalse\Z/false /; # avoid name conflicts
      @room[($room_number*$room_elements)+$d_to] = $r;
    };

    if ($line =~ /\bin_to\s+(\w+)/i ) {
      &accommodate_new_room;
      $r = "\L$1\E";
      $r =~ s/\Afalse\Z/false /; # avoid name conflicts
      @room[($room_number*$room_elements)+$in_to] = $r;
    };

    if ($line =~ /\bout_to\s+(\w+)/i ) {
      &accommodate_new_room;
      $r = "\L$1\E";
      $r =~ s/\Afalse\Z/false /; # avoid name conflicts
      @room[($room_number*$room_elements)+$out_to] = $r;
    };


  # === pattern matching: assign the before go: - directions ===

    if ($line =~ /\bbefore\b/i ) {          # detect before
           $before_detected = "true";
    };

    if ($line =~ /\bgo\s*:/i ) {            # detect go
        if ($before_detected eq "true") {   # only if before is already detected
           $go_detected = "true";
        };
    };

  # --- recognize go_objects ---

    if ($go_detected eq "true") {

      if ($line =~ /\b(n_obj)\s*:/i ) {
          $go_obj_detected = lc($1);  
      };
      if ($line =~ /\b(ne_obj)\s*:/i ) {
          $go_obj_detected = lc($1);  
      };
      if ($line =~ /\b(e_obj)\s*:/i ) {
          $go_obj_detected = lc($1);  
      };
      if ($line =~ /\b(se_obj)\s*:/i ) {
          $go_obj_detected = lc($1);  
      };
      if ($line =~ /\b(s_obj)\s*:/i ) {
          $go_obj_detected = lc($1);  
      };
      if ($line =~ /\b(sw_obj)\s*:/i ) {
          $go_obj_detected = lc($1);  
      };
      if ($line =~ /\b(w_obj)\s*:/i ) {
          $go_obj_detected = lc($1);  
      };
      if ($line =~ /\b(nw_obj)\s*:/i ) {
          $go_obj_detected = lc($1);  
      };
      if ($line =~ /\b(u_obj)\s*:/i ) {
          $go_obj_detected = lc($1);  
      };
      if ($line =~ /\b(d_obj)\s*:/i ) {
          $go_obj_detected = lc($1);  
      };

   };


  # --- beginning of before go - playerto-routines ---

    if (($go_obj_detected eq "n_obj") && ($line =~ /\bplayerto\((\w+),/i )) {
      &accommodate_new_room;
      $r = "\L$1\E";
      $r =~ s/\Afalse\Z/false /; # avoid name conflicts
      @room[($room_number*$room_elements)+$n_to] = $r;
    };
   
    if (($go_obj_detected eq "ne_obj") && ($line =~ /\bplayerto\((\w+),/i )) {
      &accommodate_new_room;
      $r = "\L$1\E";
      $r =~ s/\Afalse\Z/false /; # avoid name conflicts
      @room[($room_number*$room_elements)+$ne_to] = $r;
    };

    if (($go_obj_detected eq "e_obj") && ($line =~ /\bplayerto\((\w+),/i )) {
      &accommodate_new_room;
      $r = "\L$1\E";
      $r =~ s/\Afalse\Z/false /; # avoid name conflicts
      @room[($room_number*$room_elements)+$e_to] = $r;
    };

    if (($go_obj_detected eq "se_obj") && ($line =~ /\bplayerto\((\w+),/i )) {
      &accommodate_new_room;
      $r = "\L$1\E";
      $r =~ s/\Afalse\Z/false /; # avoid name conflicts
      @room[($room_number*$room_elements)+$se_to] = $r;
    };

    if (($go_obj_detected eq "s_obj") && ($line =~ /\bplayerto\((\w+),/i )) {
      &accommodate_new_room;
      $r = "\L$1\E";
      $r =~ s/\Afalse\Z/false /; # avoid name conflicts
      @room[($room_number*$room_elements)+$s_to] = $r;
    };

    if (($go_obj_detected eq "sw_obj") && ($line =~ /\bplayerto\((\w+),/i )) {
      &accommodate_new_room;
      $r = "\L$1\E";
      $r =~ s/\Afalse\Z/false /; # avoid name conflicts
      @room[($room_number*$room_elements)+$sw_to] = $r;
    };

    if (($go_obj_detected eq "w_obj") && ($line =~ /\bplayerto\((\w+),/i )) {
      &accommodate_new_room;
      $r = "\L$1\E";
      $r =~ s/\Afalse\Z/false /; # avoid name conflicts
      @room[($room_number*$room_elements)+$w_to] = $r;
    };

    if (($go_obj_detected eq "nw_obj") && ($line =~ /\bplayerto\((\w+),/i )) {
      &accommodate_new_room;
      $r = "\L$1\E";
      $r =~ s/\Afalse\Z/false /; # avoid name conflicts
      @room[($room_number*$room_elements)+$nw_to] = $r;
    };

    if (($go_obj_detected eq "u_obj") && ($line =~ /\bplayerto\((\w+),/i )) {
      &accommodate_new_room;
      $r = "\L$1\E";
      $r =~ s/\Afalse\Z/false /; # avoid name conflicts
      @room[($room_number*$room_elements)+$u_to] = $r;
    };

    if (($go_obj_detected eq "d_obj") && ($line =~ /\bplayerto\((\w+),/i )) {
      &accommodate_new_room;
      $r = "\L$1\E";
      $r =~ s/\Afalse\Z/false /; # avoid name conflicts
      @room[($room_number*$room_elements)+$d_to] = $r;
    };

  # --- end of before go - directions ---



  #  if ($line =~ /\bdoor_dir\s+(\w+)/i ) {
  #    &accommodate_new_room;
  #    $r = "\L$1\E";
  #    $r =~ s/\Afalse\Z/false /; # avoid name conflicts
  #    @room[($room_number*$room_elements)+$door_dir] = $r;
  #  };


   }; # endif skip commented lines
   $line_number++; # get next line

  };

}

# ------------ end of input line loop -----------------




############################################
# Load the Infocom Game File(s) into @inform
# $inform holds the main file name
############################################


# STATUS
print "Drawing a map out of the file '$inform'\n";

$room_number=-1; # initialize room counter (-1 for no room)


$input_file = $inform;		# main file = first input file


while (defined($input_file)) {	# loop for all include files

  $skip_nonfile = "false";		# for skipping nonexistent files

  unless (open(INFORMFILE, $input_file)) {
    if ($input_file eq $inform) {		# unable to open main file
      if (-e $input_file) {
         die ("Inform main file '$input_file' exists, but cannot be opened\n");
      } else {
         die ("Can't open Inform main file '$input_file'\n");
      };
    } else {
      if (-e $input_file) {
         print "Included Inform file '$input_file' exists, but cannot be opened\n";
      } else {
         print "Can't open included Inform file '$input_file'\n";
      };
      $skip_nonfile = "true";
    };
  };

  if ($skip_nonfile eq "false") {	# if it could be opened
    if ($input_file ne $inform)  {	# message only for include files
      print "Including '$input_file'\n";
    };
    &input_line_loop;		# get the whole information from the file
    close(INFORMFILE);		# close it
  };

  $input_file = pop(@file_stack);	# Include-Statements can push files
};



# -----------------------------------
# for debugging: 
# print the information got from
# the inform file
# to switch on comment out:
# - - - - - - - - - - - - - - - - - -

# &print_room_array;

# -----------------------------------

sub print_room_array {

 $t = $room_number + 1;
 print "\ntotal number of rooms: $t\n\n";

 for ($i=0;$i<=$room_number;$i++) {
   print "Room: @room[$i*$room_elements]\n";
   for ($j=1;$j<$room_elements;$j++) {
     $print = @room[($i*$room_elements)+$j];
     if ($print ne "") {
       print " $j: $print\n";
     };
   };
 };
 print "\n\n";
}



# STATUS

print "Got map data\n";







####################### SECTION 3: BUILD LOGICAL MAP ########################


#################################################
# Assigns to every room a position in a
# 3-dimensions-space @map
# ----------------------------------------------
# The Array has the length $room_number
# with three integers with the following indices:
# 0  Name of the room
# 1  x-Position  west -> east
# 2  y-Position  North -> South
# 3  z-Poistion  Down -> Up
#################################################


# ****************** Subroutines ******************

# index = room_in_map (+Room_Name)
# returns -1 if the room is not in the map
# else returns the index of the name of the room

sub room_in_map {
  my($room) = @_;
  my($i,$maplen,$out);
  $out=-1;	               # default: -1
  $maplen = int(@map/4);          # current length of the map
  for ($i=0;$i<$maplen;$i++) {    # go through every room
    if (@map[$i*4] eq $room) {    # * 4 = 1 array-entry
      $out = $i;
    };
  };
  $out;  	# returns the index for the room
}



# boolean/string = room_at_place(+x,+y,+z)
# false if there is no room at that place,
# "name" of the room if there is one 
# at this place already 

sub room_at_place {
  my($x,$y,$z) = @_;
  my($i,$maplen,$return);
  $return = "false";		# init return value
  if (($x>=0) and ($y>=0) and ($z>=0)) {; # can be < 0 in the computation
    $maplen = int(@map/4);          # current length of the map
    for ($i=0;$i<$maplen;$i++) {    # go through every room
      if ((@map[($i*4)+1] == $x) and
          (@map[($i*4)+2] == $y) and
          (@map[($i*4)+3] == $z) ) {
        $return = @map[$i*4];	# name of the room
      };
    };
  };
  $return;
}







# ----------------------------
# getting room coordinates
# by room name
# ----------------------------

# x_coord = get_room_x (+RoomName)

sub get_room_x {
  my($name) = @_;
  my($i,$maplen,$return);
  $maplen = int(@map/4);          # current length of the map
  for ($i=0;$i<$maplen;$i++) {    # go through every room
    if (@map[($i*4)] eq $name) {  # if current room is the room searched for
       $return = @map[($i*4)+1];  # store its x-coordinate
    };
  };
  $return;
}


# y_coord = get_room_y (+RoomName)

sub get_room_y {
  my($name) = @_;
  my($i,$maplen,$return);
  $maplen = int(@map/4);          # current length of the map
  for ($i=0;$i<$maplen;$i++) {    # go through every room
    if (@map[($i*4)] eq $name) {  # if current room is the room searched for
       $return = @map[($i*4)+2];  # store its y-coordinate
    };
  };
  $return;
}


# z_coord = get_room_z (+RoomName)

sub get_room_z {
  my($name) = @_;
  my($i,$maplen,$return);
  $maplen = int(@map/4);          # current length of the map
  for ($i=0;$i<$maplen;$i++) {    # go through every room
    if (@map[($i*4)] eq $name) {  # if current room is the room searched for
       $return = @map[($i*4)+3];  # store its z-coordinate
    };
  };
  $return;
}




# ----------------------------
#  shifting rooms around
#  while drawing the map
# ----------------------------


# sift_x(+Position)
# Shifts all x-coordinates of the rooms in the map
# from position x until end

sub shift_x {
  my($pos) = @_;
  my($i,$maplen);
  $maplen = int(@map/4);          # current length of the map
  for ($i=0;$i<$maplen;$i++) {    # go through every room
    if (@map[($i*4)+1] >= $pos) { # if current room is right or eq of x_pos
       @map[($i*4)+1]++;          # shift it right
    };
  };
}


# sift_y(+Position)
# Shifts all y-coordinates of the rooms in the map
# from position y until end

sub shift_y {
  my($pos) = @_;
  my($i,$maplen);
  $maplen = int(@map/4);          # current length of the map
  for ($i=0;$i<$maplen;$i++) {    # go through every room
    if (@map[($i*4)+2] >= $pos) { # if current room is right or eq of y_pos
       @map[($i*4)+2]++;          # shift it right
    };
  };
}



# sift_z(+Position)
# Shifts all z-coordinates of the rooms in the map
# from position z until end

sub shift_z {
  my($pos) = @_;
  my($i,$maplen);
  $maplen = int(@map/4);          # current length of the map
  for ($i=0;$i<$maplen;$i++) {    # go through every room
    if (@map[($i*4)+3] >= $pos) { # if current room is right or eq of z_pos
       @map[($i*4)+3]++;          # shift it right
    };
  };
}





# ---- adding of a new room ----

# add_new_room (+Room_Name)
# adds a new room to the map
# (=not connected with the map)
# under every other room

sub add_new_room {
  my($room_name) = @_;
  my($i,$maplen,$z,$max_z);
  $maplen = int(@map/4);    # current length of the map
  if ($map[0] eq "") {	# if it's the first room at all
    $map[0] = $room_name;	# add it at 0,0,0  
    $map[1] = 0;
    $map[2] = 0;
    $map[3] = 0;
  } else {		# if it's a new map in the map
    $max_z = 0;
    for ($i=0;$i<$maplen;$i++) {   # find max. z-pos
      if ($map[($i*4)+3] > $max_z) {   # i+3 = z-pos
        $max_z = $map[($i*4)+3];
      };
    };
    $z = @map;
    $map[$z] = $room_name;  # enter the new room at 0,0,(max_z+1)
    $map[$z+1] = 0;
    $map[$z+2] = 0;
    $map[$z+3] = $max_z + 1;
  };
}



# index = get_room_index (+Room)
# finding a room index to
# @room[i] by its name

sub get_room_index {
  my($room_name) = @_;
  my($i,$out);
  for($i=0;$i<=$room_number;$i++) {
    if (@room[$i*$room_elements] eq $room_name) {
      $out = $i*$room_elements;
    };
  };
  $out;		# returns the index for the room
}
  


# $current_room = next_room_left;
# compares the list of rooms detected
# against the list of rooms on the logical map
# returns "" if there is no room left,
# else the name of the next new room

sub next_room_left {
  my ($i,$room,$out);
  $out = "";		# init return

  if ($out eq "") {		# if no neighbour room found
    for ($i=0;$i<=$room_number;$i++) {	# loop trough every room detected again
      $room = @room[$i*$room_elements];
      if ((room_in_map ($room) == -1) and      # if the room is not in the map
         ($out eq "")) {		# if it's the first new room
          $out = $room;
      };
    };
  };
  
  $out;
}






# ****************** End of Subroutines ******************






# -----------------------------------
# Building of the map
# - - - - - - - - - - - - - - - - - -
# The first room in the text is taken
# as startpoint. It is added to the
# map and then every direction is
# scanned. If there is a room, 
# it becomes added to @map
# @dirs holds the directions defined
# -----------------------------------


$current_room = next_room_left;	# the first room at all
			# -> $current_room holds a room name as a string



# the p=ver/hor - flag made it necessary to
# extract the vertical directions into a subroutine,
# but logically it belongs to the loop just like the others.

sub float_up_down {

   # u_to
   $next_room = $room[$room_index+$u_to];
   if ($next_room ne "")	{		# if there IS a room upwards
     if (room_in_map($next_room) == -1) {	# if room is not on the map    

       $x = get_room_x ($current_room); 	# Position of the 
       $y = get_room_y ($current_room);	# new room
       $z = get_room_z ($current_room)-1;     

       if (room_at_place($x,$y,$z) ne "false") {	# if new pos is taken 
         shift_z($z);			# create place
       };

      if ($z == -1) {			# new room at top -> push down
         shift_z(0);                        	# all other rooms
         $z = 0;				# z-pos of the new room
       };

       $index = @map;
       $map[$index] = $next_room;		# add the new room
       $map[$index+1] = $x;
       $map[$index+2] = $y;
       $map[$index+3] = $z;

       push (@room_stack, $next_room);	# push the new room on stack

     };
   };


   # d_to
   $next_room = $room[$room_index+$d_to];
   if ($next_room ne "")	{		# if there IS a room downwards
     if (room_in_map($next_room) == -1) {	# if room is not on the map    

       $x = get_room_x ($current_room); 	# Position of the 
       $y = get_room_y ($current_room);	# new room
       $z = get_room_z ($current_room)+1;     

       if (room_at_place($x,$y,$z) ne "false") {  # if new pos is taken 
         shift_z($z);			          # create place
       };

       $index = @map;
       $map[$index] = $next_room;		# add the new room
       $map[$index+1] = $x;
       $map[$index+2] = $y;
       $map[$index+3] = $z;

       push (@room_stack, $next_room);	# push the new room on stack

     };
   };
}



# --- floats every cave ---

while ($current_room ne "") {


 # -------- floats one cave starting with $current_room -----------

 while (defined($current_room)) {	# main loop, stop if stack is empty
   if (room_in_map($current_room) == -1) {	# if room is not on the map
     add_new_room($current_room);		# add it to the map bottom
   };

   $room_index = get_room_index($current_room);


   # if u_to and d_to have priority over the same floor e.g. e_to or n_to:
   if ($prefer_dir eq "ver") {float_up_down;};


   # n_to
   $next_room = $room[$room_index+$n_to];
   if ($next_room ne "")	{		# if there IS a room nordwards
     if (room_in_map($next_room) == -1) {	# if room is not on the map    

       $x = get_room_x ($current_room); 	# Position of the 
       $y = get_room_y ($current_room)-1;	# new room
       $z = get_room_z ($current_room);     

       if (room_at_place($x,$y,$z) ne "false") { # if new pos is taken 
         shift_y($y);			         # create place
       };

       if ($y == -1) {			# new room at back -> push forward
         shift_y(0);                        	# all other rooms
         $y = 0;				# y-pos of the new room
       };

       $index = @map;
       $map[$index] = $next_room;		# add the new room
       $map[$index+1] = $x;
       $map[$index+2] = $y;
       $map[$index+3] = $z;

       push (@room_stack, $next_room);	# push the new room on stack

     };
   };


   # s_to
   $next_room = $room[$room_index+$s_to];
   if ($next_room ne "")	{		# if there IS a room southwards
     if (room_in_map($next_room) == -1) {	# if room is not on the map    

       $x = get_room_x ($current_room); 	# Position of the 
       $y = get_room_y ($current_room)+1;	# new room
       $z = get_room_z ($current_room);     

       if (room_at_place($x,$y,$z) ne "false") {	# if new pos is taken 
         shift_y($y);			# create place
       };

       $index = @map;
       $map[$index] = $next_room;		# add the new room
       $map[$index+1] = $x;
       $map[$index+2] = $y;
       $map[$index+3] = $z;

       push (@room_stack, $next_room);	# push the new room on stack

     };
   };


   # w_to
   $next_room = $room[$room_index+$w_to];
   if ($next_room ne "")	{		# if there IS a room westwards
     if (room_in_map($next_room) == -1) {	# if room is not on the map    

       $x = get_room_x ($current_room)-1; 	# Position of the 
       $y = get_room_y ($current_room);	# new room
       $z = get_room_z ($current_room);     

       if (room_at_place($x,$y,$z) ne "false") { # if new pos is taken 
         shift_x($x);			         # create place
       };

       if ($x == -1) {			# new room on left -> push
         shift_x(0);                        	# right all other rooms
         $x = 0;				# x-pos of the new room
       };

       $index = @map;
       $map[$index] = $next_room;		# add the new room
       $map[$index+1] = $x;
       $map[$index+2] = $y;
       $map[$index+3] = $z;

       push (@room_stack, $next_room);	# push the new room on stack

     };
   };


   # e_to
   $next_room = $room[$room_index+$e_to];
   if ($next_room ne "")	{		# if there IS a room eastwards
     if (room_in_map($next_room) == -1) {	# if room is not on the map    

       $x = get_room_x ($current_room)+1; 	# Position of the 
       $y = get_room_y ($current_room);	# new room
       $z = get_room_z ($current_room);     

       if (room_at_place($x,$y,$z) ne "false") {  # if new pos is taken 
         shift_x($x);			          # create place
       };

       $index = @map;
       $map[$index] = $next_room;		# add the new room
       $map[$index+1] = $x;
       $map[$index+2] = $y;
       $map[$index+3] = $z;

       push (@room_stack, $next_room);	# push the new room on stack

     };
   };


   # nw_to
   $next_room = $room[$room_index+$nw_to];
   if ($next_room ne "")	{		# if there IS a room northwestwards

     if (room_in_map($next_room) == -1) {	# if room is not on the map    

       $x = get_room_x ($current_room)-1; 	# Position of the 
       $y = get_room_y ($current_room)-1;	# new room
       $z = get_room_z ($current_room);     

       if (room_at_place($x,$y,$z) ne "false") {  # if new pos is taken 
         shift_x($x);			          # create place on the right
       };

       if ($x == -1) {			# new room on left -> push
         shift_x(0);                        	# right all other rooms
         $x = 0;				# x-pos of the new room
       };

       if ($y == -1) {			# new room at back -> push
         shift_y(0);                        	# forward all other rooms
         $y = 0;				# y-pos of the new room
       };

       $index = @map;
       $map[$index] = $next_room;		# add the new room
       $map[$index+1] = $x;
       $map[$index+2] = $y;
       $map[$index+3] = $z;

       push (@room_stack, $next_room);	# push the new room on stack

     };
   };


   # se_to
   $next_room = $room[$room_index+$se_to];
   if ($next_room ne "")	{		# if there IS a room southeastwards

     if (room_in_map($next_room) == -1) {	# if room is not on the map    

       $x = get_room_x ($current_room)+1; 	# Position of the 
       $y = get_room_y ($current_room)+1;	# new room
       $z = get_room_z ($current_room);     

       if (room_at_place($x,$y,$z) ne "false") {  # if new pos is taken 
         shift_x($x);			          # create place
       };

       $index = @map;
       $map[$index] = $next_room;		# add the new room
       $map[$index+1] = $x;
       $map[$index+2] = $y;
       $map[$index+3] = $z;

       push (@room_stack, $next_room);	# push the new room on stack

     };
   };


  # sw_to
   $next_room = $room[$room_index+$sw_to];
   if ($next_room ne "")	{		# if there IS a room northwestwards
     if (room_in_map($next_room) == -1) {	# if room is not on the map    

       $x = get_room_x ($current_room)-1; 	# Position of the 
       $y = get_room_y ($current_room)+1;	# new room
       $z = get_room_z ($current_room);     

       if (room_at_place($x,$y,$z) ne "false") {  # if new pos is taken 
         shift_x($x);			          # create place on the right
       };

       if ($x == -1) {			# new room on left -> push
         shift_x(0);                        	# right all other rooms
         $x = 0;				# x-pos of the new room
       };

       $index = @map;
       $map[$index] = $next_room;		# add the new room
       $map[$index+1] = $x;
       $map[$index+2] = $y;
       $map[$index+3] = $z;

       push (@room_stack, $next_room);	# push the new room on stack

     };
   };


  # ne_to
   $next_room = $room[$room_index+$ne_to];
   if ($next_room ne "")	{		# if there IS a room northwestwards
     if (room_in_map($next_room) == -1) {	# if room is not on the map    

       $x = get_room_x ($current_room)+1; 	# Position of the 
       $y = get_room_y ($current_room)-1;	# new room
       $z = get_room_z ($current_room);     

       if (room_at_place($x,$y,$z) ne "false") {  # if new pos is taken 
         shift_x($x);			          # create place on the right
       };

       if ($y == -1) {			# new room at back -> push
         shift_y(0);                        	# forward all other rooms
         $y = 0;				# x-pos of the new room
       };

       $index = @map;
       $map[$index] = $next_room;		# add the new room
       $map[$index+1] = $x;
       $map[$index+2] = $y;
       $map[$index+3] = $z;

       push (@room_stack, $next_room);	# push the new room on stack

     };
   };

   # if u_to and d_to don't have priority over the same room e.g. e_to or n_to:
   if ($prefer_dir eq "hor") {float_up_down;};


   $current_room = pop (@room_stack);		# loop with the next room
 }; 

 # -------- end of floating one cave -------------

 $current_room = next_room_left;	# the next map
};

# ----- end of floating every cave 





# --- compute the size of the derived map ---
# now definitive and constant

$maplen = int(@map/4);


# compute greatest x-pos
$max_x = 0;
for ($i=0;$i<$maplen;$i++) {
  $x = @map[($i*4)+1];		# actual x pos
  if ($x > $max_x) {		# max x pos
    $max_x=$x;
  };
};

# compute greatest y-pos
$max_y = 0;
for ($i=0;$i<$maplen;$i++) {
  $y = @map[($i*4)+2];		# actual x pos
  if ($y > $max_y) {		# max x pos
    $max_y=$y;
  };
};

# compute greatest z-pos
$max_z = 0;
for ($i=0;$i<$maplen;$i++) {
  $z = @map[($i*4)+3];		# actual x pos
  if ($z > $max_z) {		# max x pos
    $max_z=$z;
  };
};




# -----------------------------------
# for debugging: 
# print the logical map on screen
# (every room with its coordinates)
# to switch on comment out:
# - - - - - - - - - - - - - - - - - -

# &print_room_map;

# -----------------------------------

sub print_room_map {

  my($i,$maplen);
  $maplen = int(@map/4);       # current length of the map
  for ($i=0;$i<$maplen;$i++) {
    print "@map[($i*4)+1], ";
    print "@map[($i*4)+2], ";
    print "@map[($i*4)+3]:  "; 
    print "@map[($i*4)]\n";
  };
  print "\n\n";
}



# ---------------- End of Building of the Map itself






#################### SECTION 4: BUILD LOGICAL DIRECTIONS ########################


# -----------------------------------
# Building of the connections
# (graphical connections)
# - - - - - - - - - - - - - - - - - -
# This loops through the logical
# map and scans the attached 
# directions for every room.
# It creates a new array
# for every direction, e.g.:
# @map_w_e  dirtype, (see below)
#           x1,y1,z1, (the room itself)
#           x2,x2,z2  (the endpoint of the line)
#                   (7 elements)
#
#
# w_e --- XXXXXX
#      _/  / | \   
#    _/   /  |  \
# sw_ne  s_n |se_nw
#           d_u
# -----------------------------------
# if the directions are unary
# (n->s but no way back)
# it's mentioned as follows:
# 0: binary direction
# 1: direction away from room FROM
# 2: direction to room TO
#
# The arrays:
# @map_s_n
# @map_w_e
# @map_sw_ne
# @map_se_nw
# @map_d_u
# -----------------------------------
# if the connections cannot
# be regurarly drawn, they
# come into the 4-element-array
# @map_name_n  name,
#              x,y,z   (4 elements)
# There is an array for every
# direction, e.g
# @map_name_n
# @map_name_nw
# @map_name_w
# ...
# -----------------------------------

# number of elements in a directions map (constant)
$n_map_dir = 7;	# N elements for MAP DIRections

# the direction codes (constants)
$bin = 0;
$from = 1;
$to = 2;


# next_DIRECTION (x,y,z)
# these routines (which the direction as suffix)
#  grab the next room to each compass direction
#  straightly forward
# 45DEG-directions (e.g. ne) are only
#  taken if they match exact 45DEG
# updates the global variables
#  $next_x
#  $next_y
#  $next_z
#  with the coordinates of the room found

# u_to
sub room_next_u {
  my($x,$y,$z) = @_;
  my($i,$room,$out);
  $out = "";				# initial value
  for ($i=$z-1;$i>=0;$i--) { 
    $room = room_at_place($x,$y,$i); 
    if (($out eq "") and ($room ne "false")) {	# if room not found yet
      $out = $room;			# store next room
      $next_x = $x;
      $next_y = $y;
      $next_z = $i;
    };
  };
  $out;
}

# d_to
sub room_next_d {
  my($x,$y,$z) = @_;
  my($i,$room,$out);
  $out = "";
  for ($i=$z+1;$i<=$max_z;$i++) { 
    $room = room_at_place($x,$y,$i); 
    if (($out eq "") and ($room ne "false")) {
      $out = $room;
      $next_x = $x;
      $next_y = $y;
      $next_z = $i;
    };
  };
  $out;
}

# n_to
sub room_next_n {
  my($x,$y,$z) = @_;
  my($i,$room,$out);
  $out = "";
  for ($i=$y-1;$i>=0;$i--) { 
    $room = room_at_place($x,$i,$z); 
    if (($out eq "") and ($room ne "false")) {
      $out = $room;
      $next_x = $x;
      $next_y = $i;
      $next_z = $z;
    };
  };
  $out;
}

# s_to
sub room_next_s {
  my($x,$y,$z) = @_;
  my($i,$room,$out);
  $out = "";
  for ($i=$y+1;$i<=$max_y;$i++) { 
    $room = room_at_place($x,$i,$z); 
    if (($out eq "") and ($room ne "false")) {
      $out = $room;
      $next_x = $x;
      $next_y = $i;
      $next_z = $z;
    };
  };
  $out;
}

# w_to
sub room_next_w {
  my($x,$y,$z) = @_;
  my($i,$room,$out);
  $out = "";
  for ($i=$x-1;$i>=0;$i--) { 
    $room = room_at_place($i,$y,$z); 
    if (($out eq "") and ($room ne "false")) {
      $out = $room;
      $next_x = $i;
      $next_y = $y;
      $next_z = $z;
    };
  };
  $out;
}

# e_to
sub room_next_e {
  my($x,$y,$z) = @_;
  my($i,$room,$out);
  $out = "";
  for ($i=$x+1;$i<=$max_x;$i++) { 
    $room = room_at_place($i,$y,$z); 
    if (($out eq "") and ($room ne "false")) {
      $out = $room;
      $next_x = $i;
      $next_y = $y;
      $next_z = $z;
    };
  };
  $out;
}

# nw_to
# main counter for n
sub room_next_nw {
  my($x,$y,$z) = @_;
  my($i,$j,$d,$room,$out);
  $out = "";
  $j=0;		# counter for w
  for ($i=$y-1;$i>=0;$i--) {
    $j--;
    $room = room_at_place($x+$j,$i,$z); 
    if (($out eq "") and ($room ne "false") and (($x+$j)>=0)) {
      $out = $room;
      $next_x = $x+$j;
      $next_y = $i;
      $next_z = $z;
    };
  };
  $out;
}

# se_to
# main counter for s
sub room_next_se {
  my($x,$y,$z) = @_;
  my($i,$j,$d,$room,$out);
  $out = "";
  $j=0;		# counter for e
  for ($i=$y+1;$i<=$max_y;$i++) {
    $j++;
    $room = room_at_place($x+$j,$i,$z); 
    if (($out eq "") and ($room ne "false")) {
      $out = $room;
      $next_x = $x+$j;
      $next_y = $i;
      $next_z = $z;
    };
  };
  $out;
}

# ne_to
# main counter for n
sub room_next_ne {
  my($x,$y,$z) = @_;
  my($i,$j,$d,$room,$out);
  $out = "";
  $j=0;		# counter for e
  for ($i=$y-1;$i>=0;$i--) {
    $j++;
    $room = room_at_place($x+$j,$i,$z); 
    if (($out eq "") and ($room ne "false")) {
      $out = $room;
      $next_x = $x+$j;
      $next_y = $i;
      $next_z = $z;
    };
  };
  $out;
}

# sw_to
# main counter for s
sub room_next_sw {
  my($x,$y,$z) = @_;
  my($i,$j,$d,$room,$out);
  $out = "";
  $j=0;		# counter for w
  for ($i=$y+1;$i<=$max_y;$i++) {
    $j--;
    $room = room_at_place($x+$j,$i,$z); 
    if (($out eq "") and ($room ne "false") and (($x+$j)>=0)) {
      $out = $room;
      $next_x = $x+$j;
      $next_y = $i;
      $next_z = $z;
    };
  };
  $out;
}

# --- end of next_DIRECTION ---




# --- get_map_DIR(x,y,z) ---
# e.g.: number = get_map_s_n(x,y,z)
# returns -1 if there is no connection at that pos,
# else the index of the found connection


# for down_up-direction
sub get_map_d_u {
  my($x,$y,$z) = @_;
  my($i,$stop,$out);
  $out = -1;		# init out
  $stop = int(@map_d_u/$n_map_dir);	# length of the map
  for ($i=0;$i<$stop;$i++) {	# loop through all dirs in the map
    if ((@map_d_u[($i*$n_map_dir)+1] == $x) and  # succeeds if there is a direction
        (@map_d_u[($i*$n_map_dir)+2] == $y) and  # at that place
        (@map_d_u[($i*$n_map_dir)+3] == $z)) {
      $out = $i*$n_map_dir;			# the index (only one possible)
    };
  };
  $out;
}

# for south_north-direction
sub get_map_s_n {
  my($x,$y,$z) = @_;
  my($i,$stop,$out);
  $out = -1;		# init out
  $stop = int(@map_s_n/$n_map_dir);	# length of the map
  for ($i=0;$i<$stop;$i++) {	# loop through all dirs in the map
    if ((@map_s_n[($i*$n_map_dir)+1] == $x) and  # succeeds if there is a direction
        (@map_s_n[($i*$n_map_dir)+2] == $y) and  # at that place
        (@map_s_n[($i*$n_map_dir)+3] == $z)) {
      $out = $i*$n_map_dir;			# the index (only one possible)
    };
  };
  $out;
}

# for west_east-direction
sub get_map_w_e {
  my($x,$y,$z) = @_;
  my($i,$stop,$out);
  $out = -1;		# init out
  $stop = int(@map_w_e/$n_map_dir);	# length of the map
  for ($i=0;$i<$stop;$i++) {	# loop through all dirs in the map
    if ((@map_w_e[($i*$n_map_dir)+1] == $x) and  # succeeds if there is a direction
        (@map_w_e[($i*$n_map_dir)+2] == $y) and  # at that place
        (@map_w_e[($i*$n_map_dir)+3] == $z)) {
      $out = $i*$n_map_dir;			# the index (only one possible)
    };
  };
  $out;
}

# for southwest_northeast-direction
sub get_map_sw_ne {
  my($x,$y,$z) = @_;
  my($i,$stop,$out);
  $out = -1;		# init out
  $stop = int(@map_sw_ne/$n_map_dir);	# length of the map
  for ($i=0;$i<$stop;$i++) {	# loop through all dirs in the map
    if ((@map_sw_ne[($i*$n_map_dir)+1] == $x) and  # succeeds if there is a direction
        (@map_sw_ne[($i*$n_map_dir)+2] == $y) and  # at that place
        (@map_sw_ne[($i*$n_map_dir)+3] == $z)) {
      $out = $i*$n_map_dir;			# the index (only one possible)
    };
  };
  $out;
}

# for southeast_northwest-direction
sub get_map_se_nw {
  my($x,$y,$z) = @_;
  my($i,$stop,$out);
  $out = -1;		# init out
  $stop = int(@map_se_nw/$n_map_dir);	# length of the map
  for ($i=0;$i<$stop;$i++) {	# loop through all dirs in the map
    if ((@map_se_nw[($i*$n_map_dir)+1] == $x) and  # succeeds if there is a direction
        (@map_se_nw[($i*$n_map_dir)+2] == $y) and  # at that place
        (@map_se_nw[($i*$n_map_dir)+3] == $z)) {
      $out = $i*$n_map_dir;			# the index (only one possible)
    };
  };
  $out;
}




# --- build up connections main routine ---


$maplen = int(@map/4);
for ($i=0;$i<$maplen;$i++) {		# loop trough the rooms in the map

  $name = @map[($i*4)];		# get name & coordinates of this room
  $x = @map[($i*4)+1];
  $y = @map[($i*4)+2]; 
  $z = @map[($i*4)+3];

  $index = get_room_index($name);	# $index is not defined if room not declared,
  if (defined($index)) {		#   but mentioned in a direction
				#    -> lines only possible TO

# ---- d_u (down-up)-pair ----

    # u_to
    # line is attached to the room upwards of room!
    $next_room = $room[$index+$u_to];		# --- room upwards of $name ---
    if ($next_room ne "") 	{		# if there is a room upwards

      if (room_next_u($x,$y,$z) eq $next_room) { # and on drawable place up

        $ix = @map_d_u;			# index to new entry for direction
        $inext = get_map_d_u($next_x,$next_y,$next_z); # globals by room_next_...
					# index for the next room in dirs
        if ($inext == -1) {			# if no connection already declared
          $map_d_u[$ix] = $to;		# direction TO (seen from upwards)
          $map_d_u[$ix+1] = $next_x;		# create new entry
          $map_d_u[$ix+2] = $next_y;		# dir attached to the UP room !!
          $map_d_u[$ix+3] = $next_z;
          $map_d_u[$ix+4] = $x;		# endpoint of line
          $map_d_u[$ix+5] = $y;
          $map_d_u[$ix+6] = $z;
        } else {				# else it is already declared
          $map_d_u[$inext] = $bin;		# change it to BINARY direction
        };

      } else {				# road to next room is not drawable
        $jx = get_room_index($next_room);
        if (defined($jx) and 		# if next_room declared
            ($room[$jx+$d_to] eq $name)) {	# and points to this room
              $next_room_out = $next_room;	# it is bidirectional
        } else {
              $next_room_out = ">$next_room";	# mark single directions
        };
        $ix = @map_name_u;			# index to new entry for
        $map_name_u[$ix] = $next_room_out;	# room to be printed
        $map_name_u[$ix+1] = $x;		# on THIS room !!
        $map_name_u[$ix+2] = $y;
        $map_name_u[$ix+3] = $z;
      };
    };


    # d_to
    # line is attached to the room itself!
    $next_room = $room[$index+$d_to];		# --- room downwards of $name ---
    if ($next_room ne "") 	{		# if there is a room downwards

      if (room_next_d($x,$y,$z) eq $next_room) { # and on drawable place down

        $ix = @map_d_u;			# index to new entry for direction
        $iatt = get_map_d_u($x,$y,$z);      	# $i for the attach-room (= this room)

        if ($iatt == -1) {			# if no connection already declared
          $map_d_u[$ix] = $from;		# direction FROM (seen from here)
          $map_d_u[$ix+1] = $x;		# create new entry
          $map_d_u[$ix+2] = $y;		# dir attached to here !!
          $map_d_u[$ix+3] = $z;
          $map_d_u[$ix+4] = $next_x;		# endpoint of line to down
          $map_d_u[$ix+5] = $next_y;
          $map_d_u[$ix+6] = $next_z;
        } else {				# else it is already declared
          $map_d_u[$iatt] = 0;		# change it to BINARY direction
        };

      } else {				# road to next room is not drawable
        $jx = get_room_index($next_room);
        if (defined($jx) and 		# if next_room declared
            ($room[$jx+$u_to] eq $name)) {	# and points to this room
              $next_room_out = $next_room;	# it is bidirectional
        } else {
              $next_room_out = ">$next_room";	# mark single directions
        };
        $ix = @map_name_d;			# index to new south(!)-entry for
        $map_name_d[$ix] = $next_room_out;	# room to be printed
        $map_name_d[$ix+1] = $x;		# on THIS room !!
        $map_name_d[$ix+2] = $y;
        $map_name_d[$ix+3] = $z;
      };
    };



# ---- s_n (south-north)-pair ----

    # n_to
    # line is attached to the room nordwards of room!
    $next_room = $room[$index+$n_to];		# --- room northwards of $name ---
    if ($next_room ne "") 	{		# if there is a room northwards

      if (room_next_n($x,$y,$z) eq $next_room) { # and on drawable place north

        $ix = @map_s_n;			# index to new entry for direction
        $inext = get_map_s_n($next_x,$next_y,$next_z); # globals by room_next_...
					# index for the next room in dirs
        if ($inext == -1) {			# if no connection already declared
          $map_s_n[$ix] = $to;		# direction TO (seen from nordwards)
          $map_s_n[$ix+1] = $next_x;		# create new entry
          $map_s_n[$ix+2] = $next_y;		# dir attached to the NORTH room !!
          $map_s_n[$ix+3] = $next_z;
          $map_s_n[$ix+4] = $x;		# endpoint of line
          $map_s_n[$ix+5] = $y;
          $map_s_n[$ix+6] = $z;
        } else {				# else it is already declared
          $map_s_n[$inext] = $bin;		# change it to BINARY direction
        };

      } else {				# road to next room is not drawable
        $jx = get_room_index($next_room);
        if (defined($jx) and 		# if next_room declared
            ($room[$jx+$s_to] eq $name)) {	# and points to this room
              $next_room_out = $next_room;	# it is bidirectional
        } else {
              $next_room_out = ">$next_room";	# mark single directions
        };
        $ix = @map_name_n;			# index to new entry for
        $map_name_n[$ix] = $next_room_out;	# room to be printed
        $map_name_n[$ix+1] = $x;		# on THIS room !!
        $map_name_n[$ix+2] = $y;
        $map_name_n[$ix+3] = $z;
      };
    };


    # s_to
    # line is attached to the room itself!
    $next_room = $room[$index+$s_to];		# --- room southwards of $name ---
    if ($next_room ne "") 	{		# if there is a room southwards

      if (room_next_s($x,$y,$z) eq $next_room) { # and on drawable place south

        $ix = @map_s_n;			# index to new entry for direction
        $iatt = get_map_s_n($x,$y,$z);      	# $i for the attach-room (= this room)

        if ($iatt == -1) {			# if no connection already declared
          $map_s_n[$ix] = $from;		# direction FROM (seen from here)
          $map_s_n[$ix+1] = $x;		# create new entry
          $map_s_n[$ix+2] = $y;		# dir attached to here !!
          $map_s_n[$ix+3] = $z;
          $map_s_n[$ix+4] = $next_x;		# endpoint of line to the south
          $map_s_n[$ix+5] = $next_y;
          $map_s_n[$ix+6] = $next_z;
        } else {				# else it is already declared
          $map_s_n[$iatt] = 0;		# change it to BINARY direction
        };

      } else {				# road to next room is not drawable
        $jx = get_room_index($next_room);
        if (defined($jx) and 		# if next_room declared
            ($room[$jx+$n_to] eq $name)) {	# and points to this room
              $next_room_out = $next_room;	# it is bidirectional
        } else {
              $next_room_out = ">$next_room";	# mark single directions
        };
        $ix = @map_name_s;			# index to new south(!)-entry for
        $map_name_s[$ix] = $next_room_out;	# room to be printed
        $map_name_s[$ix+1] = $x;		# on THIS room !!
        $map_name_s[$ix+2] = $y;
        $map_name_s[$ix+3] = $z;
      };
    };



# ---- w_e (west-east)-pair ----

    # e_to
    # line is attached to the room eastwards of room!
    $next_room = $room[$index+$e_to];		# --- room eastwards of $name ---
    if ($next_room ne "") 	{		# if there is a room eastwards

      if (room_next_e($x,$y,$z) eq $next_room) { # and on drawable place east

        $ix = @map_w_e;			# index to new entry for direction
        $inext = get_map_w_e($next_x,$next_y,$next_z); # globals by room_next_...
					# index for the next room in dirs
        if ($inext == -1) {			# if no connection already declared
          $map_w_e[$ix] = $to;		# direction TO (seen from eastwards)
          $map_w_e[$ix+1] = $next_x;		# create new entry
          $map_w_e[$ix+2] = $next_y;		# dir attached to the EAST room !!
          $map_w_e[$ix+3] = $next_z;
          $map_w_e[$ix+4] = $x;		# endpoint of line
          $map_w_e[$ix+5] = $y;
          $map_w_e[$ix+6] = $z;
        } else {				# else it is already declared
          $map_w_e[$inext] = $bin;		# change it to BINARY direction
        };

      } else {				# road to next room is not drawable
        $jx = get_room_index($next_room);
        if (defined($jx) and 		# if next_room declared
            ($room[$jx+$w_to] eq $name)) {	# and points to this room
              $next_room_out = $next_room;	# it is bidirectional
        } else {
              $next_room_out = ">$next_room";	# mark single directions
        };
        $ix = @map_name_e;			# index to new entry for
        $map_name_e[$ix] = $next_room_out;	# room to be printed
        $map_name_e[$ix+1] = $x;		# on THIS room !!
        $map_name_e[$ix+2] = $y;
        $map_name_e[$ix+3] = $z;
      };
    };


    # w_to
    # line is attached to the room itself!
    $next_room = $room[$index+$w_to];		# --- room westwards of $name ---
    if ($next_room ne "") 	{		# if there is a room westwards

      if (room_next_w($x,$y,$z) eq $next_room) { # and on drawable place west

        $ix = @map_w_e;			# index to new entry for direction
        $iatt = get_map_w_e($x,$y,$z);      	# $i for the attach-room (= this room)

        if ($iatt == -1) {			# if no connection already declared
          $map_w_e[$ix] = $from;		# direction FROM (seen from here)
          $map_w_e[$ix+1] = $x;		# create new entry
          $map_w_e[$ix+2] = $y;		# dir attached to here !!
          $map_w_e[$ix+3] = $z;
          $map_w_e[$ix+4] = $next_x;		# endpoint of line to the west
          $map_w_e[$ix+5] = $next_y;
          $map_w_e[$ix+6] = $next_z;
        } else {				# else it is already declared
          $map_w_e[$iatt] = 0;		# change it to BINARY direction
        };

      } else {				# road to next room is not drawable
        $jx = get_room_index($next_room);
        if (defined($jx) and 		# if next_room declared
            ($room[$jx+$e_to] eq $name)) {	# and points to this room
              $next_room_out = $next_room;	# it is bidirectional
        } else {
              $next_room_out = ">$next_room";	# mark single directions
        };
        $ix = @map_name_w;			# index to new south(!)-entry for
        $map_name_w[$ix] = $next_room_out;	# room to be printed
        $map_name_w[$ix+1] = $x;		# on THIS room !!
        $map_name_w[$ix+2] = $y;
        $map_name_w[$ix+3] = $z;
      };
    };



# ---- sw_ne (southwest-northeast)-pair ----

    # ne_to
    # line is attached to the room northeastwards of room!
    $next_room = $room[$index+$ne_to];	# --- room northeastwards of $name ---
    if ($next_room ne "") 	{		# if there is a room northeastwards

      if (room_next_ne($x,$y,$z) eq $next_room) { # and on drawable place northeast

        $ix = @map_sw_ne;			# index to new entry for direction
        $inext = get_map_sw_ne($next_x,$next_y,$next_z); # globals by room_next_...
					# index for the next room in dirs
        if ($inext == -1) {			# if no connection already declared
          $map_sw_ne[$ix] = $to;		# direction TO (seen from ne-wards)
          $map_sw_ne[$ix+1] = $next_x;	# create new entry
          $map_sw_ne[$ix+2] = $next_y;	# dir attached to the NORTHEAST room !!
          $map_sw_ne[$ix+3] = $next_z;
          $map_sw_ne[$ix+4] = $x;		# endpoint of line
          $map_sw_ne[$ix+5] = $y;
          $map_sw_ne[$ix+6] = $z;
        } else {				# else it is already declared
          $map_sw_ne[$inext] = $bin;		# change it to BINARY direction
        };

      } else {				# road to next room is not drawable
        $jx = get_room_index($next_room);
        if (defined($jx) and 		# if next_room declared
            ($room[$jx+$sw_to] eq $name)) {	# and points to this room
              $next_room_out = $next_room;	# it is bidirectional
        } else {
              $next_room_out = ">$next_room";	# mark single directions
        };
        $ix = @map_name_ne;			# index to new entry for
        $map_name_ne[$ix] = $next_room_out;	# room to be printed
        $map_name_ne[$ix+1] = $x;		# on THIS room !!
        $map_name_ne[$ix+2] = $y;
        $map_name_ne[$ix+3] = $z;
      };
    };


    # sw_to
    # line is attached to the room itself!
    $next_room = $room[$index+$sw_to];	# --- room southwestwards of $name ---
    if ($next_room ne "") 	{		# if there is a room southwestwards

      if (room_next_sw($x,$y,$z) eq $next_room) { # and on drawable place southwest

        $ix = @map_sw_ne;			# index to new entry for direction
        $iatt = get_map_sw_ne($x,$y,$z);      	# $i for the attach-room (= this room)

        if ($iatt == -1) {			# if no connection already declared
          $map_sw_ne[$ix] = $from;		# direction FROM (seen from here)
          $map_sw_ne[$ix+1] = $x;		# create new entry
          $map_sw_ne[$ix+2] = $y;		# dir attached to here !!
          $map_sw_ne[$ix+3] = $z;
          $map_sw_ne[$ix+4] = $next_x;	# endpoint of line to the southwest
          $map_sw_ne[$ix+5] = $next_y;
          $map_sw_ne[$ix+6] = $next_z;
        } else {				# else it is already declared
          $map_sw_ne[$iatt] = 0;		# change it to BINARY direction
        };

      } else {				# road to next room is not drawable
        $jx = get_room_index($next_room);
        if (defined($jx) and 		# if next_room declared
            ($room[$jx+$ne_to] eq $name)) {	# and points to this room
              $next_room_out = $next_room;	# it is bidirectional
        } else {
              $next_room_out = ">$next_room";	# mark single directions
        };
        $ix = @map_name_sw;			# index to new south(!)-entry for
        $map_name_sw[$ix] = $next_room_out;	# room to be printed
        $map_name_sw[$ix+1] = $x;		# on THIS room !!
        $map_name_sw[$ix+2] = $y;
        $map_name_sw[$ix+3] = $z;
      };
    };



# ---- se_nw (southwest-northeast)-pair ----

    # nw_to
    # line is attached to the room northwestwards of room!
    $next_room = $room[$index+$nw_to];	# --- room northwestwards of $name ---
    if ($next_room ne "") 	{		# if there is a room northwestwards

      if (room_next_nw($x,$y,$z) eq $next_room) { # and on drawable place northwest

        $ix = @map_se_nw;			# index to new entry for direction
        $inext = get_map_se_nw($next_x,$next_y,$next_z); # globals by room_next_...
					# index for the next room in dirs
        if ($inext == -1) {			# if no connection already declared
          $map_se_nw[$ix] = $to;		# direction TO (seen from ne-wards)
          $map_se_nw[$ix+1] = $next_x;	# create new entry
          $map_se_nw[$ix+2] = $next_y;	# dir attached to the NORTHWEST room !!
          $map_se_nw[$ix+3] = $next_z;
          $map_se_nw[$ix+4] = $x;		# endpoint of line
          $map_se_nw[$ix+5] = $y;
          $map_se_nw[$ix+6] = $z;
        } else {				# else it is already declared
          $map_se_nw[$inext] = $bin;		# change it to BINARY direction
        };

      } else {				# road to next room is not drawable
        $jx = get_room_index($next_room);
        if (defined($jx) and 		# if next_room declared
            ($room[$jx+$se_to] eq $name)) {	# and points to this room
              $next_room_out = $next_room;	# it is bidirectional
        } else {
              $next_room_out = ">$next_room";	# mark single directions
        };
        $ix = @map_name_nw;			# index to new entry for
        $map_name_nw[$ix] = $next_room_out;	# room to be printed
        $map_name_nw[$ix+1] = $x;		# on THIS room !!
        $map_name_nw[$ix+2] = $y;
        $map_name_nw[$ix+3] = $z;
      };
    };


    # se_to
    # line is attached to the room itself!
    $next_room = $room[$index+$se_to];	# --- room southeastwards of $name ---
    if ($next_room ne "") 	{		# if there is a room southeastwards

      if (room_next_se($x,$y,$z) eq $next_room) { # and on drawable place southeast

        $ix = @map_se_nw;			# index to new entry for direction
        $iatt = get_map_se_nw($x,$y,$z);      	# $i for the attach-room (= this room)

        if ($iatt == -1) {			# if no connection already declared
          $map_se_nw[$ix] = $from;		# direction FROM (seen from here)
          $map_se_nw[$ix+1] = $x;		# create new entry
          $map_se_nw[$ix+2] = $y;		# dir attached to here !!
          $map_se_nw[$ix+3] = $z;
          $map_se_nw[$ix+4] = $next_x;	# endpoint of line to the southeast
          $map_se_nw[$ix+5] = $next_y;
          $map_se_nw[$ix+6] = $next_z;
        } else {				# else it is already declared
          $map_se_nw[$iatt] = 0;		# change it to BINARY direction
        };

      } else {				# road to next room is not drawable
        $jx = get_room_index($next_room);
        if (defined($jx) and 		# if next_room declared
            ($room[$jx+$nw_to] eq $name)) {	# and points to this room
              $next_room_out = $next_room;	# it is bidirectional
        } else {
              $next_room_out = ">$next_room";	# mark single directions
        };
        $ix = @map_name_se;			# index to new south(!)-entry for
        $map_name_se[$ix] = $next_room_out;	# room to be printed
        $map_name_se[$ix+1] = $x;		# on THIS room !!
        $map_name_se[$ix+2] = $y;
        $map_name_se[$ix+3] = $z;
      };
    };



  };
};





# -----------------------------------
# for debugging: 
# print the logical map directions
# to switch on comment out:
# - - - - - - - - - - - - - - - - - -

# &print_room_dirs;

# -----------------------------------

sub print_room_dirs {

  my($i,$dirlen,$name);


# d_u-pair
  $dirlen = int(@map_d_u/$n_map_dir);       # down-up-directions
  print "#down-up (down of):\n";
  for ($i=0;$i<$dirlen;$i++) {
    $name = room_at_place(@map_d_u[($i*$n_map_dir)+1],
                          @map_d_u[($i*$n_map_dir)+2],
                          @map_d_u[($i*$n_map_dir)+3]);
    $nname = room_at_place(@map_d_u[($i*$n_map_dir)+4],
                          @map_d_u[($i*$n_map_dir)+5],
                          @map_d_u[($i*$n_map_dir)+6]);
    print "$name to $nname: @map_d_u[($i*$n_map_dir)]\n";
  };

  $dirlen = int(@map_name_d/4);	# names in the west
  print "#names down from-to:\n";
  for ($i=0;$i<$dirlen;$i++) {
    $name = room_at_place(@map_name_d[($i*4)+1],
                          @map_name_d[($i*4)+2],
                          @map_name_d[($i*4)+3]);
    print "$name: @map_name_d[($i*4)]\n";
  };

  $dirlen = int(@map_name_u/4);	# names in the east
  print "#names up from-to:\n";
  for ($i=0;$i<$dirlen;$i++) {
    $name = room_at_place(@map_name_u[($i*4)+1],
                          @map_name_u[($i*4)+2],
                          @map_name_u[($i*4)+3]);
    print "$name: @map_name_u[($i*4)]\n";
  };
  print "\n";



# s_n-pair
  $dirlen = int(@map_s_n/$n_map_dir);       # south-north-directions
  print "#south-north (south of):\n";
  for ($i=0;$i<$dirlen;$i++) {
    $name = room_at_place(@map_s_n[($i*$n_map_dir)+1],
                          @map_s_n[($i*$n_map_dir)+2],
                          @map_s_n[($i*$n_map_dir)+3]);
    $nname = room_at_place(@map_s_n[($i*$n_map_dir)+4],
                          @map_s_n[($i*$n_map_dir)+5],
                          @map_s_n[($i*$n_map_dir)+6]);
    print "$name to $nname: @map_s_n[($i*$n_map_dir)]\n";
  };

  $dirlen = int(@map_name_s/4);	# names in the south
  print "#names south from-to:\n";
  for ($i=0;$i<$dirlen;$i++) {
    $name = room_at_place(@map_name_s[($i*4)+1],
                          @map_name_s[($i*4)+2],
                          @map_name_s[($i*4)+3]);
    print "$name: @map_name_s[($i*4)]\n";
  };

  $dirlen = int(@map_name_n/4);	# names in the north
  print "#names north from-to:\n";
  for ($i=0;$i<$dirlen;$i++) {
    $name = room_at_place(@map_name_n[($i*4)+1],
                          @map_name_n[($i*4)+2],
                          @map_name_n[($i*4)+3]);
    print "$name: @map_name_n[($i*4)]\n";
  };
  print "\n";


# w_e-pair
  $dirlen = int(@map_w_e/$n_map_dir);       # west-east-directions
  print "#west-east (west of):\n";
  for ($i=0;$i<$dirlen;$i++) {
    $name = room_at_place(@map_w_e[($i*$n_map_dir)+1],
                          @map_w_e[($i*$n_map_dir)+2],
                          @map_w_e[($i*$n_map_dir)+3]);
    $nname = room_at_place(@map_w_e[($i*$n_map_dir)+4],
                          @map_w_e[($i*$n_map_dir)+5],
                          @map_w_e[($i*$n_map_dir)+6]);
    print "$name to $nname: @map_w_e[($i*$n_map_dir)]\n";
  };

  $dirlen = int(@map_name_w/4);	# names in the west
  print "#names west from-to:\n";
  for ($i=0;$i<$dirlen;$i++) {
    $name = room_at_place(@map_name_w[($i*4)+1],
                          @map_name_w[($i*4)+2],
                          @map_name_w[($i*4)+3]);
    print "$name: @map_name_w[($i*4)]\n";
  };

  $dirlen = int(@map_name_e/4);	# names in the east
  print "#names east from-to:\n";
  for ($i=0;$i<$dirlen;$i++) {
    $name = room_at_place(@map_name_e[($i*4)+1],
                          @map_name_e[($i*4)+2],
                          @map_name_e[($i*4)+3]);
    print "$name: @map_name_e[($i*4)]\n";
  };
  print "\n";


# sw_ne-pair
  $dirlen = int(@map_sw_ne/$n_map_dir);       # southwest-northeast-directions
  print "#southwest-northeast (southwest of):\n";
  for ($i=0;$i<$dirlen;$i++) {
    $name = room_at_place(@map_sw_ne[($i*$n_map_dir)+1],
                          @map_sw_ne[($i*$n_map_dir)+2],
                          @map_sw_ne[($i*$n_map_dir)+3]);
    $nname = room_at_place(@map_sw_ne[($i*$n_map_dir)+4],
                          @map_sw_ne[($i*$n_map_dir)+5],
                          @map_sw_ne[($i*$n_map_dir)+6]);
    print "$name to $nname: @map_sw_ne[($i*$n_map_dir)]\n";
  };

  $dirlen = int(@map_name_sw/4);	# names in the southwest
  print "#names southwest from-to:\n";
  for ($i=0;$i<$dirlen;$i++) {
    $name = room_at_place(@map_name_sw[($i*4)+1],
                          @map_name_sw[($i*4)+2],
                          @map_name_sw[($i*4)+3]);
    print "$name: @map_name_sw[($i*4)]\n";
  };

  $dirlen = int(@map_name_ne/4);	# names in the northeast
  print "#names northeast from-to:\n";
  for ($i=0;$i<$dirlen;$i++) {
    $name = room_at_place(@map_name_ne[($i*4)+1],
                          @map_name_ne[($i*4)+2],
                          @map_name_ne[($i*4)+3]);
    print "$name: @map_name_ne[($i*4)]\n";
  };
  print "\n";


# se_nw-pair
  $dirlen = int(@map_se_nw/$n_map_dir);       # southeast-northwest-directions
  print "#southeast-northwest (southwest of):\n";
  for ($i=0;$i<$dirlen;$i++) {
    $name = room_at_place(@map_se_nw[($i*$n_map_dir)+1],
                          @map_se_nw[($i*$n_map_dir)+2],
                          @map_se_nw[($i*$n_map_dir)+3]);
    $nname = room_at_place(@map_se_nw[($i*$n_map_dir)+4],
                          @map_se_nw[($i*$n_map_dir)+5],
                          @map_se_nw[($i*$n_map_dir)+6]);
    print "$name to $nname: @map_se_nw[($i*$n_map_dir)]\n";
  };

  $dirlen = int(@map_name_se/4);	# names in the southeast
  print "#names southeast from-to:\n";
  for ($i=0;$i<$dirlen;$i++) {
    $name = room_at_place(@map_name_se[($i*4)+1],
                          @map_name_se[($i*4)+2],
                          @map_name_se[($i*4)+3]);
    print "$name: @map_name_se[($i*4)]\n";
  };

  $dirlen = int(@map_name_nw/4);	# names in the northeast
  print "#names nortwest from-to:\n";
  for ($i=0;$i<$dirlen;$i++) {
    $name = room_at_place(@map_name_nw[($i*4)+1],
                          @map_name_nw[($i*4)+2],
                          @map_name_nw[($i*4)+3]);
    print "$name: @map_name_nw[($i*4)]\n";
  };
  print "\n";

}


# ----------------- End of building the connections




# STATUS

print "Created logical map\n";









####################### SECTION 5: BUILD GRAPHICAL MAP ########################


######################################
# first compute the x-size of the map
# (y-size not easily computable)
# $drawing_size_x

# $room_width comes from the command line

# this variables serve as constants 
# they are not strictly independent of each other
# (e.g. room_space_x and room_space_y)
# -> leave them as they are to avoid (really) ugly maps
# (count starts from 1)

$room_size_x = $room_width + 4 + 2; 	# width of a room  (with 2 lines)
$room_size_y = 2 + 2;		# height of a room (with 2 lines)

$room_space_x = 7+2;		# horizontal space between rooms
$room_space_y = 1 + 3;		# vertical space >=4 between rooms

$room_grid_x = $room_size_x + $room_space_x;
$room_grid_y = $room_size_y + $room_space_y;

$draw_offset_init = 3;		# init for $draw_offset up->down (on map drawing)
$draw_offset_z = 6;		# space between two "floors"

# $maplen = (@map/4);		# from here on static !! (moved upwards)



# computable after max_, max_y:

$drawing_offset_xy =  (($max_y+1)*$room_size_y) +	# x-offset on y-change
                      ($max_y*$room_space_y); 		# for all rooms

#					this is the maximal 2D-width
$drawing_size_x = (($max_x+1)*$room_size_x) +	# number on one x * real width 
                  ($max_x*$room_space_x) +	# spaces = number - 1
                  $drawing_offset_xy; 




##############################################
# draw map into array @drawing
# -------------------------------------------
# Begin in the upper right corner and
# draw from right->left  up->down
############################################## 


# put_char(char,x,y)
# put a char on a certain position 
# in the 2D-array @drawing
# Attention: x and y have their
# normal 2d-meaning

$lowest_point = 0;		# reset "lowest point" of the graphic (max y)
$leftmost_point = $drawing_size_x;		# for avoiding space on the left
$rightmost_point = 0;			# for avoiding space on the right

sub put_char {
  my($char,$x_2d,$y_2d) = @_;
  if ( ($x_2d>=0) and ($x_2d<$drawing_size_x) and ($y_2d>=0) ) {
    @drawing [ $y_2d*$drawing_size_x + $x_2d ] = $char;
    if ($y_2d > $lowest_point) {
      $lowest_point = $y_2d;
    };
    if ($x_2d < $leftmost_point) {
      $leftmost_point = $x_2d;
    };
    if ($x_2d > $rightmost_point) {
      $rightmost_point = $x_2d;
    };
  } else {
     print"### failed to put char '$char' on $x_2d,$y_2d\n";
  };
}



# draw_char(char,x,y)
# 3D-put-char-projection
# simulates 3d-printing
# on one floor
# (with down-offset
#  $draw_offset)
# x,y are char coordinates, 
# not logical coordinates!

#            ----> x-coord
#           /|
#          / |
#         L  v
#  y-coord   z-coord wiht $draw_offset 

sub draw_char {
  my($char,$x,$y) = @_;
  my($xm,$ym);
  $xm = $x - $y + $drawing_offset_xy;
  $ym = $y + $draw_offset;
  put_char($char,$xm,$ym);
}





# draw_room(name,x,y)
# draws a room at the
# logical position x,y
# (on one floor)

sub draw_room {
  my($name,$x_in,$y_in) = @_;
  my($stop,$xp,$x,$yp,$y,$i,$len);	# $xp and $yp are 2D-coordinates!

  # draw the two horizontal lines
  $xp = $room_grid_x * $x_in;
  $stop = $xp + $room_size_x-1;	# here: start from 0
  $yp = $room_grid_y * $y_in;
  for ($x=$xp;$x<$stop;$x++) {
     draw_char("_",$x,$yp);
     draw_char("_",$x,$yp+$room_size_y-1);	# -1: starting from 0
  };

  # draw the two vertical lines
  $x = $xp;
  $y = $yp;				# under the upper left corner
  for ($i=1;$i<$room_size_y;$i++) {		# -> $i=1
    draw_char("/",$x,$y+$i);
    draw_char("/",($x+$room_size_x-1),$y+$i);
  };
 
  # draw the name of the room
  $len = length($name);		# for centering the name
  if ($len > $room_width) {
    $len = $room_width;
  };
  $i = int( ($room_width-$len) / 2) ;		# leading spaces before name
  $x = $xp + 3 + $i;			# beginning of the string
  $y = $yp + 2;
  for ($i=0;$i<$len;$i++) {
    draw_char (substr($name,$i,1),$x+$i,$y);	# draw char by char
  };

}



# number = empty_rows_y (floor)
# to compress output graphics compute number of rows
# that are blank (from y=0 to ...)
# -> gives a negative drawing offset for each floor

sub empty_rows_y {
  my($floor) = @_;
  my($return,$pfloor,$y,$z,$local_y);

  $return = 0;			# init return

  if ($floor > 0) {		# if it's not the first floor (z=0)
     $pfloor = $floor - 1;		# compute previous floor:
     $local_y = 0;			# find "most at front" - y
     for ($i=0;$i<$maplen;$i++) {
       $y = @map[($i*4)+2];
       $z = @map[($i*4)+3];
       if (($z == $pfloor) and ($y > $local_y)) {
          $local_y = $y;
       };
     };
     $return = $max_y - $local_y;	# -> number of empty rows in front
  };


  $local_y = $max_y;		# compute the "most at back" - y
  for ($i=0;$i<$maplen;$i++) {	# on the floor
     $y = @map[($i*4)+2];
     $z = @map[($i*4)+3];
     if (($z == $floor) and ($y < $local_y)) {
        $local_y = $y;
     };
  };

  $return = ($return + $local_y) * $room_grid_y; 

  $return;
}






# ------- The subroutines for the connections ----------

# ----------------------------------------------
# draw the lines (''=bn ---, _to > >, _from < <


sub draw_line_w_e {	# the coordinates are (east point,_,west point)
  my ($x1,$y1,$x2,$style) = @_;	#	  	-> $x1 > $x2 
  my ($ystop,$ystart,$xp);
  $xstart = ($room_grid_x * $x2) + $room_size_x + 1;
  $xstop = ($room_grid_x * $x1) - 2;
  $yp = ($room_grid_y * $y1) + 2;
  if ($style == $bin) {			# line like -----
    for ($xp=$xstart;$xp<=$xstop;$xp++) {
      draw_char("-",$xp,$yp);
    };
  } else {			# line like > > or < <
    for ($xp=$xstart;$xp<=$xstop;$xp=$xp+2) {
      if ($style == $to) {
        draw_char(">",$xp,$yp);
      } else {
        draw_char("<",$xp,$yp);
      };
    };
  };
}


sub draw_line_s_n {	# the coordinates are (north point,_,south point)
  my ($x1,$y1,$y2,$style) = @_;	#	  	-> $y1 < $2
  my( $ystop,$ystart,$xp);
  $ystart = ($room_grid_y * $y1) + $room_size_y + 1;
  $ystop = ($room_grid_y * $y2) - 1;
  $xp = ($room_grid_x * $x1) + int ($room_size_x/2);
  if ($style == $bin) {			# line like |
    for ($yp=$ystart;$yp<=$ystop;$yp++) {	#           |
      draw_char("/",$xp,$yp);
    };
  } else {			# line like ^ or v
    for ($yp=$ystart;$yp<=$ystop;$yp++) {
      if ($style == $to) {
        draw_char("^",$xp,$yp);
      } else {
        draw_char("v",$xp,$yp);
      };
    };
  };
}


sub draw_line_sw_ne {	# the coordinates are (northeast - southwest)
  my ($x1,$y1,$x2,$y2,$style) = @_;
  my ($ystart,$ystop,$xp);
  $xp = ($room_grid_x * $x1);
  $ystart = ($room_grid_y * $y1) + $room_size_y;
  $ystop = ($room_grid_y * $y2) - 1;
  if ($style == $bin) {			# line like  ___
    for ($yp=$ystart;$yp<=$ystop;$yp++) {	#        ___/
      draw_char("_",$xp,$yp);
      draw_char("_",$xp-1,$yp);
      draw_char("_",$xp-2,$yp);
      if ($yp != $ystop) {	# suppress last / downwards
        draw_char("/",$xp-2,$yp+1);
      };
     $xp = $xp - 3;		# for the perspective
    };
  } else {			# line like > or <
    $xp--;	# looks better
    for ($yp=$ystart;$yp<=$ystop;$yp++) {
      if ($style == $to) {
        draw_char(">",$xp,$yp);
      } else {
        draw_char("<",$xp,$yp);
      };
      $xp = $xp - 3;
    };
  };
}


sub draw_line_se_nw {	# the coordinates are (northwest - southeast)
  my ($x1,$y1,$x2,$y2,$style) = @_;
  my ($ystart,$ystop,$xp);
  $xp = ($room_grid_x * $x1) + $room_size_x + 2;	# looks best
  $ystart = ($room_grid_y * $y1) + $room_size_y + 1;
  $ystop = ($room_grid_y * $y2) - 1;
  if ($style == $bin) {			# line like \
    for ($yp=$ystart;$yp<=$ystop;$yp++) {	#            \
      draw_char("\\",$xp,$yp);	# ! Perl ! is the single char \
      $xp = $xp + 2;	# watch perspective
    };
  } else {			# line like > or <
    for ($yp=$ystart;$yp<=$ystop;$yp++) {
      if ($style == $to) {
        draw_char("^",$xp,$yp);
      } else {
        draw_char("v",$xp,$yp);
      };
      $xp = $xp + 2;
    };
  };
}




# -------------------------------
# draw_room_name(Room,x,y)
# draw (=prints) a room name
# centered on a 2D-position
# on a defined floor
# uses $room_width!
# ">room"-rooms are recognized
# as single direction rooms

sub draw_room_name {
  my($room,$xp,$yp) = @_;
  my ($deliminiter,$len,$i,$x,$y);

  $len = length($room);
  if (substr($room,0,1) eq ">") {	# if single direction
    $room = substr($room,1,$len-1);	# delete the ">"
    $deliminiter = ">";
  } else {
    $deliminiter = "-";
  };

  $len = length($room);		# again, for centering the name
  if ($len > ($room_width-2)) {	# -2 for the /deliminiters/
    $len = $room_width-2;
  };
  $x = $xp -  int($len/2) - 1;		# alignment on the left
  $y = $yp;
  draw_char ($deliminiter,$x,$y);		# left room deliminiter
  draw_char ($deliminiter,$x+$len+1,$y);	# right deliminiter
  for ($i=0;$i<$len;$i++) {
    draw_char (substr($room,$i,1),$x+$i+1,$y);	# draw char by char
  };
}



# -----------------------------------
# draw_map_name_[dir] (name,x,y)
# draw names for not drawable lines
# for each (really each) direction
# x and y are logical coordinates!


sub draw_map_name_w {
  my($name,$x_in,$y_in) = @_;
  my($x,$y);
  $x = ($room_grid_x * $x_in);
  $y = ($room_grid_y * $y_in) + 2;
  draw_room_name($name,$x,$y);  
}

sub draw_map_name_e {
  my($name,$x_in,$y_in) = @_;
  my($x,$y);
  $x = ($room_grid_x * $x_in) + $room_size_x;
  $y = ($room_grid_y * $y_in) + 2;
  draw_room_name($name,$x,$y);  
}

sub draw_map_name_nw {
  my($name,$x_in,$y_in) = @_;
  my($x,$y);
  $x = ($room_grid_x * $x_in);
  $y = ($room_grid_y * $y_in) + 1;
  draw_room_name($name,$x,$y);  
}

sub draw_map_name_ne {
  my($name,$x_in,$y_in) = @_;
  my($x,$y);
  $x = ($room_grid_x * $x_in) + $room_size_x;
  $y = ($room_grid_y * $y_in) + 1;
  draw_room_name($name,$x,$y);  
}

sub draw_map_name_sw {
  my($name,$x_in,$y_in) = @_;
  my($x,$y);
  $x = ($room_grid_x * $x_in);
  $y = ($room_grid_y * $y_in) + 3;
  draw_room_name($name,$x,$y);  
}

sub draw_map_name_se {
  my($name,$x_in,$y_in) = @_;
  my($x,$y);
  $x = ($room_grid_x * $x_in) + $room_size_x;
  $y = ($room_grid_y * $y_in) + 3;
  draw_room_name($name,$x,$y);  
}

sub draw_map_name_n { 
  my($name,$x_in,$y_in) = @_;
  my($x,$y);
  $x = ($room_grid_x * $x_in) + int($room_size_x/2);
  $y = ($room_grid_y * $y_in) + 1;
  draw_room_name($name,$x,$y);  
}

sub draw_map_name_s {
  my($name,$x_in,$y_in) = @_;
  my($x,$y);
  $x = ($room_grid_x * $x_in) + int($room_size_x/2);
  $y = ($room_grid_y * $y_in) + 3;
  draw_room_name($name,$x,$y);  
}

sub draw_map_name_u {		# up is different
  my($name,$x_in,$y_in) = @_;
  my($x,$y);
  $x = ($room_grid_x * $x_in) + int($room_size_x/2) - 3;
  $y = ($room_grid_y * $y_in) - 1;
  draw_char("|",$x,$y);
  draw_room_name($name,$x-1,$y-1);  
}

sub draw_map_name_d {		# down is different
  my($name,$x_in,$y_in) = @_;
  my($x,$y);
  $x = ($room_grid_x * $x_in) + int($room_size_x/2) + 2;
  $y = ($room_grid_y * $y_in) + 4;
  draw_char("|",$x,$y);
  draw_room_name($name,$x+1,$y+1);  
}



# ------- end of subroutines for the connections -------






# ======= draw the map, each floor separately =======
# sets up the array
# @draw_offset_on_floor[$z]
# which holds the draw offset for each floor
# for further additions to the drawing


$draw_offset = $draw_offset_init;

for ($z=0;$z<=$max_z;$z++) {		# for each floor

  # draw floor $z

  $draw_offset = $draw_offset - empty_rows_y($z);	# adjust draw offset
  $draw_offset_on_floor[$z] = $draw_offset;		# store it in array

  for ($i=0;$i<$maplen;$i++) {	# loop trough every room on the map
    if (@map[($i*4)+3] == $z) { 	# select if room is on the right floor
      $name = @map[$i*4];
      $x = @map[($i*4)+1];
      $y = @map[($i*4)+2];
      draw_room ($name,$x,$y);
    };
  };

  $draw_offset = $draw_offset +	# for next floor
                 $drawing_offset_xy +
                 $draw_offset_z; 

};

# ---------- end of drawing the room map --------------






# ======= draw the connections, each floor separately =======


for ($z=0;$z<=$max_z;$z++) {		# for each floor

  # --- draw connections on floor $z ---

 $draw_offset = $draw_offset_on_floor[$z];	# adjust draw offset


  # w_e-pairs
  $dirlen = int(@map_w_e/$n_map_dir);       # west-east-directions
  for ($i=0;$i<$dirlen;$i++) {
    if (@map_w_e[($i*$n_map_dir)+3] == $z) {	# only if on the right floor
      $x1 = @map_w_e[($i*$n_map_dir)+1];	# starting of the line
      $y1 = @map_w_e[($i*$n_map_dir)+2];
      $x2 = @map_w_e[($i*$n_map_dir)+4];	# ($y2 == $y1)
      $style = @map_w_e[($i*$n_map_dir)];
      draw_line_w_e($x1,$y1,$x2,$style);
    };
  };

  $dirlen = int(@map_name_w/4);	# names in the west
  for ($i=0;$i<$dirlen;$i++) {
    if (@map_name_w[($i*4)+3] == $z) {	# only if on the right floor
      $x = @map_name_w[($i*4)+1];
      $y = @map_name_w[($i*4)+2];
      $name = @map_name_w[($i*4)];
      draw_map_name_w($name,$x,$y);
    };
  };

  $dirlen = int(@map_name_e/4);	# names in the east
  for ($i=0;$i<$dirlen;$i++) {
    if (@map_name_e[($i*4)+3] == $z) {
      $x = @map_name_e[($i*4)+1];
      $y = @map_name_e[($i*4)+2];
      $name = @map_name_e[($i*4)];
      draw_map_name_e($name,$x,$y);
    };
  };



  # s_n-pairs
  $dirlen = int(@map_s_n/$n_map_dir);       	# south-north-directions
  for ($i=0;$i<$dirlen;$i++) {
    if (@map_s_n[($i*$n_map_dir)+3] == $z) {	# only if on the right floor
      $x1 = @map_s_n[($i*$n_map_dir)+1];	# starting of the line
      $y1 = @map_s_n[($i*$n_map_dir)+2];
      $y2 = @map_s_n[($i*$n_map_dir)+5];	# ($x2 == $x1)
      $style = @map_s_n[($i*$n_map_dir)];
      draw_line_s_n($x1,$y1,$y2,$style);
    };
  };

  $dirlen = int(@map_name_s/4);	# names in the south
  for ($i=0;$i<$dirlen;$i++) {
    if (@map_name_s[($i*4)+3] == $z) {	# only if on the right floor
      $x = @map_name_s[($i*4)+1];
      $y = @map_name_s[($i*4)+2];
      $name = @map_name_s[($i*4)];
      draw_map_name_s($name,$x,$y);
    };
  };

  $dirlen = int(@map_name_n/4);	# names in the north
  for ($i=0;$i<$dirlen;$i++) {
    if (@map_name_n[($i*4)+3] == $z) {
      $x = @map_name_n[($i*4)+1];
      $y = @map_name_n[($i*4)+2];
      $name = @map_name_n[($i*4)];
      draw_map_name_n($name,$x,$y);
    };
  };



  # sw_ne-pairs
  $dirlen = int(@map_sw_ne/$n_map_dir);	# southwest-northeast-directions
  for ($i=0;$i<$dirlen;$i++) {
    if (@map_sw_ne[($i*$n_map_dir)+3] == $z) {	# only if on the right floor
      $x1 = @map_sw_ne[($i*$n_map_dir)+1];	# starting of the line
      $y1 = @map_sw_ne[($i*$n_map_dir)+2];
      $x2 = @map_sw_ne[($i*$n_map_dir)+4];
      $y2 = @map_sw_ne[($i*$n_map_dir)+5];
      $style = @map_sw_ne[($i*$n_map_dir)];
      draw_line_sw_ne($x1,$y1,$x2,$y2,$style);
    };
  };

  $dirlen = int(@map_name_sw/4);	# names in the southwest
  for ($i=0;$i<$dirlen;$i++) {
    if (@map_name_sw[($i*4)+3] == $z) {	# only if on the right floor
      $x = @map_name_sw[($i*4)+1];
      $y = @map_name_sw[($i*4)+2];
      $name = @map_name_sw[($i*4)];
      draw_map_name_sw($name,$x,$y);
    };
  };

  $dirlen = int(@map_name_ne/4);	# names in the northeast
  for ($i=0;$i<$dirlen;$i++) {
    if (@map_name_ne[($i*4)+3] == $z) {
      $x = @map_name_ne[($i*4)+1];
      $y = @map_name_ne[($i*4)+2];
      $name = @map_name_ne[($i*4)];
      draw_map_name_ne($name,$x,$y);
    };
  };



  # se_nw-pairs
  $dirlen = int(@map_se_nw/$n_map_dir);	# southeast-northwest-directions
  for ($i=0;$i<$dirlen;$i++) {
    if (@map_se_nw[($i*$n_map_dir)+3] == $z) {	# only if on the right floor
      $x1 = @map_se_nw[($i*$n_map_dir)+1];	# starting of the line
      $y1 = @map_se_nw[($i*$n_map_dir)+2];
      $x2 = @map_se_nw[($i*$n_map_dir)+4];
      $y2 = @map_se_nw[($i*$n_map_dir)+5];
      $style = @map_se_nw[($i*$n_map_dir)];
      draw_line_se_nw($x1,$y1,$x2,$y2,$style);
    };
  };

  $dirlen = int(@map_name_se/4);	# names in the southeast
  for ($i=0;$i<$dirlen;$i++) {
    if (@map_name_se[($i*4)+3] == $z) {	# only if on the right floor
      $x = @map_name_se[($i*4)+1];
      $y = @map_name_se[($i*4)+2];
      $name = @map_name_se[($i*4)];
      draw_map_name_se($name,$x,$y);
    };
  };

  $dirlen = int(@map_name_nw/4);	# names in the northwest
  for ($i=0;$i<$dirlen;$i++) {
    if (@map_name_nw[($i*4)+3] == $z) {
      $x = @map_name_nw[($i*4)+1];
      $y = @map_name_nw[($i*4)+2];
      $name = @map_name_nw[($i*4)];
      draw_map_name_nw($name,$x,$y);
    };
  };



  # d_u-pairs
  $dirlen = int(@map_d_u/$n_map_dir);	# down-up-directions
  for ($i=0;$i<$dirlen;$i++) {
    if (@map_d_u[($i*$n_map_dir)+3] == $z) {	# only if on the right floor
      $x1 = @map_d_u[($i*$n_map_dir)+1];	# starting of the line
      $y1 = @map_d_u[($i*$n_map_dir)+2];
      $z1 = @map_d_u[($i*$n_map_dir)+3];
      $x2 = @map_d_u[($i*$n_map_dir)+4];
      $y2 = @map_d_u[($i*$n_map_dir)+5];
      $z2 = @map_d_u[($i*$n_map_dir)+6];
      $style = @map_d_u[($i*$n_map_dir)];
      push (@stack_draw_d_u, ($x1,$y1,$z1,$x2,$y2,$z2,$style));  # on stack!
    };
  };

  $dirlen = int(@map_name_d/4);	# names downwards
  for ($i=0;$i<$dirlen;$i++) {
    if (@map_name_d[($i*4)+3] == $z) {	# only if on the right floor
      $x = @map_name_d[($i*4)+1];
      $y = @map_name_d[($i*4)+2];
      $name = @map_name_d[($i*4)];
      draw_map_name_d($name,$x,$y);
    };
  };

  $dirlen = int(@map_name_u/4);	# names upwards
  for ($i=0;$i<$dirlen;$i++) {
    if (@map_name_u[($i*4)+3] == $z) {
      $x = @map_name_u[($i*4)+1];
      $y = @map_name_u[($i*4)+2];
      $name = @map_name_u[($i*4)];
      draw_map_name_u($name,$x,$y);
    };
  };


};




# ========= draw the up-down-connections at last =========
# They are held in the Array 
# @stack_draw_d_u[n] = ($x1,$y1,$z1,$x2,$y2,$z2,$style)


# pop the first line
$style = pop(@stack_draw_d_u);
$z2 = pop(@stack_draw_d_u);
$y2 = pop(@stack_draw_d_u);
$x2 = pop(@stack_draw_d_u);
$z1 = pop(@stack_draw_d_u);
$y1 = pop(@stack_draw_d_u);
$x1 = pop(@stack_draw_d_u);



while (defined($x1)) {

  # first part from up to down

  $offset1 = $draw_offset_on_floor[$z1];		# z-offset 1
  $x3d1 = ($room_grid_x * $x1) + int ($room_size_x / 2) + 2;
  $y3d1 = ($room_grid_y * $y1) + int ($room_size_y / 2) + 2; 

  $x2d1 = $x3d1 - $y3d1 + $drawing_offset_xy;
  $y2d1 = $y3d1 + $offset1;

  $index2d = ($y2d1 * $drawing_size_x) + $x2d1;	# index for start of the line

  for ($i=0;$i<=$room_space_y-2;$i++) {
    $drawindex = $index2d + ($i*$drawing_size_x);
    if ($style == $bin) {
      $drawing [$drawindex] = "|";
    };
    if ($style == $to) {
      $drawing [$drawindex] = "^";
    };
    if ($style == $from) {
      $drawing [$drawindex] = "v";
    };
  };
  $dp_index1 = $index2d+(($room_space_y-1)*$drawing_size_x);
  $drawing [$dp_index1] = ":"; # last char of line


  # second part from down to up

  $offset2 = $draw_offset_on_floor[$z2];		# z-offset 2
#  $x3d2 = ($room_grid_x * $x2) + int ($room_size_x / 2) + 2;  #not needed
  $y3d2 = ($room_grid_y * $y1) + int ($room_size_y / 2) - 2; 

#  $x2d2 = $x3d2 - $y3d2 + $drawing_offset_xy;  #not needed
  $y2d2 = $y3d2 + $offset2;

  $index2d = ($y2d2 * $drawing_size_x) + $x2d1;	# index for start of the line 
                                                # it's the same as from up-down

  for ($i=0;$i<=$room_space_y-2;$i++) {
    $drawindex = $index2d - ($i*$drawing_size_x);	# upwards
    if ($style == $bin) {
      $drawing [$drawindex] = "|";
    };
    if ($style == $to) {
      $drawing [$drawindex] = "^";
    };
    if ($style == $from) {
      $drawing [$drawindex] = "v";
    };
  };
  $dp_index2 = $index2d-(($room_space_y-1)*$drawing_size_x);
  $char = $drawing[$dp_index2];
  if ($char ne ":") {
    $drawing [$dp_index2] = ":"; # last char of line
  } else {
    if ($style == $bin) {
      $drawing [$dp_index2] = "|";
    };
    if ($style == $to) {
      $drawing [$dp_index2] = "^";
    };
    if ($style == $from) {
      $drawing [$dp_index2] = "v";
    };
  };


  # print lose dot connections between two rooms (afterwards!)

  $dp_index1 = $dp_index1 + ($drawing_size_x * 3);	# init value
  while ($dp_index2 > $dp_index1) {
    $drawing [$dp_index1]  = ".";
    $dp_index1 = $dp_index1 + ($drawing_size_x * 3);	# continue
  };


  # pop next room
  $style = pop(@stack_draw_d_u);
  $z2 = pop(@stack_draw_d_u);
  $y2 = pop(@stack_draw_d_u);
  $x2 = pop(@stack_draw_d_u);
  $z1 = pop(@stack_draw_d_u);
  $y1 = pop(@stack_draw_d_u);
  $x1 = pop(@stack_draw_d_u);
};



# ------------ end of drawing the connections ----------------









####################### SECTION 6: SAVE GRAPHICAL MAP ########################



#######################
# save map into file(s)
# If the map is larger
# than $column_width
# draw multiple maps
#######################

# draws only the really printed map width ("if point in space")


if ($column_width >= $drawing_size_x) {	# --- single file for 1 column ---

  $outfile = "$outfile_name$outfile_suffix$outfile_type";

# STATUS
  print "Saving '$outfile'\n";

  unless (open(OUTFILE, ">$outfile")) {
    die ("Can't write to output file '$outfile'\n");
  };

    $drawing_size_y = int(@drawing/$drawing_size_x)+1;

    for ($y=0;$y<$drawing_size_y;$y++) {	# every line
      $out_buffer = "";			# reset output line buffer

      $y_offset = $drawing_size_x * $y;	# offset into @drawing-array

      for ($x=$leftmost_point;$x<$drawing_size_x;$x++) {	# draw each line
        if ($x <= $rightmost_point) {		# put only if in space
          $char = $drawing[$y_offset+$x];
          if ($char eq "") {
            $out_buffer = "$out_buffer ";	# add space to buffer
          } else {
            $out_buffer = "$out_buffer$char";	# else add char to buffer
          };
        };
      };

      print OUTFILE "$out_buffer\n";		# write one line to output
    };

  close(OUTFILE);


} else {					# --- multiple files for n columns ---


  $column_number = int($drawing_size_x/$column_width)+1;
  if ($column_number>999) {
    print "Abort due to $column_number columns...\n";
    die ("-> increase the 'c=$column_width' flag\n");
  };


  $outfile_body = "$outfile_name$outfile_suffix";

# STATUS
  print "Saving the columns '$outfile_body.xxx$outfile_type'\n";

  for ($j=0;$j<$column_number;$j++) {		# loop through the columns

    if ($j<=999) {$digit = "$j";}; 
    if ($j<=99) {$digit = "0$j";};
    if ($j<=9) {$digit = "00$j";};
    if ($j==0) {$digit = "000";};


    if ( (($j*$column_width)+$leftmost_point)	# leftmost point of this column 
               <= $rightmost_point) {		# open file if point in space 

      unless (open(OUTFILE, ">$outfile_body.$digit$outfile_type")) {
        die ("Can't write to output file '$outfile'\n");
      };

        $drawing_size_y = int(@drawing/$drawing_size_x)+1;

        for ($y=0;$y<$drawing_size_y;$y++) {	# every line
          $out_buffer = "";			# reset output line buffer

          $y_offset = $drawing_size_x * $y;	# offset into @drawing-array

          $x_start = ($j*$column_width)+$leftmost_point;
          if ($j == ($column_number-1)) {	# last column
              $x_end = $drawing_size_x;
          } else {
              $x_end = $x_start + $column_width;	# intermediate column
          };

          for ($x=$x_start;$x<$x_end;$x++) {		# draw each line
            $char = $drawing[$y_offset+$x];
            if ($x <= $rightmost_point) {		# put only if in space
              if ($char eq "") {
                $out_buffer = "$out_buffer ";		# add space to buffer
              } else {
                $out_buffer = "$out_buffer$char";	# else add char to buffer
              };
            };
          };

          print OUTFILE "$out_buffer\n";		# write one line to output
        };

      close(OUTFILE);
    };

  };
};





# STATUS

print "Done\n";

####################### end of INFORMAP "float the cave" ########################
