!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!
!     Utility.h                         A library of reasonably useful
!                                       Inform 6 functions by
!       V 4.0                           L. Ross Raszewski
!
! New in 4.0: Glulx support (requires infglk)
!             Finally fixed the "strict mode" conflict in center
!             New functions:
!               Abs, Pow, BoldIt, SInsert, ScriptPrint,
!               get_window_from_stream (glulx only)
! New in 3.2: New functions: Age, DaemonRunning, TimerRunning
! New in 3.1: Automatic V6lib support, new function: LocateCursor
!               Special thanks to Jason C. Penny for V6 modifications
! New in 3.0: New function: Rmove
!             Moved Center and CenterU to Utility.h
! New in 2.1: I learned to spell "Underline"
! New in 2.0:  Symbolic constants for Emphasis system.
!              New Documentation
!              Slight change to Emphasis.
!
! I've recenly realized that I've been using functions in my libraries as if
! everyone had them, when in fact, they don't.  The surprising lack of
! commentary I've gotten on these has resulted in my not having noticed this
! sooner.  This library contains all the non-standard functions called by my
! libraries.  These functions are also available for public use.  A
! description of each appears before it
!
! e-mail me at [email protected]
ifndef WORDSIZE;
Constant WORDSIZE 2;
Constant TARGET_ZCODE;
endif;
ifdef TARGET_GLULX;
include "infglk";
endif;
System_File;
ifndef UTILITY_LIBRARY;
Constant UTILITY_LIBRARY 32;
ifndef strict;
global strict=0;
endif;
ifndef temp_obj;
Object temp_obj;
endif;
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
! Pmove - moves obj1 into obj2 as the youngest child
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
[ Pmove obj1 obj2 o;
  for (o=child(obj2):o ofclass Object: o=child(obj2)) move o to temp_obj;
  move obj1 to obj2;
  for (o=child(temp_obj):o ofclass Object: o=child(temp_obj)) move o to obj2;
];
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
! Rmove - moves obj1 as the immediate younger sibling of obj2
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
[ Rmove obj1 obj2 o i;
  i=parent(obj2);
  for(o=child(i):o~=obj2:o=child(i)) move o to temp_obj;
  move obj2 to temp_obj;
  move obj1 to i;
  for(o=child(temp_obj):o ofclass Object:o=child(temp_obj)) move o to i;
];
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
! Emphasis - changes the text emphasis setting
!          The global variable Emphasis_Color stores the color for
!          Emphasis(3);  The default is green.
!            Emphasis(0) - normal text
!            Emphasis(1) - bold
!            Emphasis(2) - Underline
!            Emphasis(3) - Color (if available)
!            Emphasis(4) - Reverse
!          To use Emphasis in a print statement, be sure to use the inform
!          format for embedded print statements:
!          "This word is in ", (Emphasis) COLOR, "color", (Emphasis) NORMAL,
!          ".";
!         The symbolic constants below can be used in place of numbers.
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
Constant NORMAL 0;
Constant BOLD   1;
Constant UNDERLINE 2;
Constant COLOR 3;
Constant REVERSE 4;
! Color Settings
Constant DFLT 1;
Constant BLACK 2;
Constant RED 3;
Constant GREEN 4;
Constant YELLOW 5;
Constant BLUE 6;
Constant MAGENTA 7;
Constant CYAN 8;
Constant WHITE 9;
Global Emphasis_Color=4;        ! Default color is green
[ Emphasis n;
#ifdef TARGET_ZCODE;
switch(n){
0: style roman;
#ifndef SPECTEST_AVAILABLE;
        if (standard_interpreter>=2 ) @set_colour 1 1;
#ifnot;
       if (standard_interpreter>=2 || Spec->ColorFlag) @set_colour 1 1;
#endif;
1: style bold;
2: style underline;
3:
if (Emphasis_Color==-1) style reverse;
else if (Emphasis_Color==-2) print "*";
else {
#ifndef SPECTEST_AVAILABLE;
       if ( (standard_interpreter) >= 2&& (0->1)&1)
        @set_colour Emphasis_Color 1;
       else style underline;
#ifnot;
       if ( ((standard_interpreter) >= 2 || Spec->ColorFlag)  && (0->1)&1)
        @set_colour Emphasis_Color 1;
       else style underline;
#endif;
}
4: style reverse;
}
#ifnot;
switch(n)
{
0: glk_set_style(style_Normal);
1: glk_set_style(style_Emphasized);
2: glk_set_style(style_User1);
3: glk_set_style(style_User2);
4: glk_set_style(style_BlockQuote);
}
#endif;
];

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
! WaitForKey - waits for a keypress.  Takes as an argument a string to be
!              printed.  if none is given, it prints the default.
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
[ WaitForKey str;
if (str==0) str="[Press Any Key]";
if (str ofclass string) print (string) str;
else if (str ofclass routine) indirect(str);
#ifdef TARGET_ZCODE;
@read_char 1 str;
#ifnot;
KeyCharPrimitive();
#endif;

];


!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
! Scion - Finds a child of certain "age"; scion(o,1) is the child of an object
!         scion(o,2) is the sibling of the child, and so on.
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

[ Scion Object x i;
       if (x==0) return Object;
       x--;
       i=child(Object);
       while (x>0 && i~=nothing)
        { i=sibling(i); x--; }
       return i;
];
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
! Age -  Returns the "age" of a object, such that the eldest child of an
!        object has age 1, and so on; Scion(parent(x),Age(x))==x
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
[ Age obj x y;
  x=1;
  y=child(parent(obj));
  while (y~=obj)
  {
   x++;
   y=sibling(y);
  }
  return x;
];
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
! Center - Centers a line of text on the current line
!       Center(x); where x is a line of text or a routine to print one
!       (this routine shoud ONLY print text, as it will be called twice)
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
Array CenterText -> 80;
[ Center instring i;
#ifdef TARGET_ZCODE;
   CenterText-->0 = 78;
   @output_stream 3 CenterText;
   if (instring ofclass string)
       print (string) instring;
   if (instring ofclass Routine)
       indirect(instring);
   @output_stream -3;
   #Ifdef V6DEFS_H;
   i = ActiveZWindow.GetXSize();
   i = i - 0-->($30/2);
   i = i/2;
   ActiveZWindow.SetCursor(0, i);
   #Ifnot;
   i = 0->$21;
   i = i - CenterText-->0;
   i = i/2;
   font off;
   spaces(i);
   #endif;
   if (instring ofclass string)
       print (string) instring;
   if (instring ofclass Routine)
       indirect(instring);
  #ifndef V6DEFS_H;
   font on;
  #endif;
#ifnot;
glk_window_get_size(get_window_from_stream(glk_stream_get_current()),
                    gg_arguments,gg_arguments+WORDSIZE);
i=PrintAnyToArray(CenterText,80,instring);
glk_set_style(style_Preformatted);
spaces(((gg_arguments-->0)-i)/2);
PrintAnything(instring);

glk_set_style(style_Normal);
#endif;

];


!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
! CenterU - Centers a line of text in the upper window
!           CenterU(x,y) where y is the line of the upper window on which to
!           print the line
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
[ CenterU instring j i;
#ifdef TARGET_ZCODE;
   CenterText-->0 = 128;
   @output_stream 3 CenterText;
   if (instring ofclass string)
       print (string) instring;
   if (instring ofclass Routine)
       indirect(instring);
   @output_stream -3;
   #Ifdef V6DEFS_H;
   i = ActiveZWindow.GetXSize();
   i = i - 0-->($30/2);
   i = i/2;
   ActiveZWindow.SetCursorByChar(j,0);
   ActiveZWindow.SetCursor(0, i);
   #Ifnot;
   i = 0->$21;
   i = i - CenterText-->0;
   i = i/2;
   @set_cursor j i;
   #endif;
   if (instring ofclass string)
       print (string) instring;
   if (instring ofclass Routine)
       indirect(instring);
#ifnot;
glk_window_get_size(get_window_from_stream(glk_stream_get_current()),
                    gg_arguments,gg_arguments+WORDSIZE);
j=PrintAnyToArray(CenterText,80,instring);

LocateCursor(i,(gg_arguments-->0-j)/2);
PrintAnything(instring);

! glk_set_style(style_Normal);


#endif;

];
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
! LocateCursor - places the cursor within the upper window
!                LocateCursor(y,x) places the cursor at position x,y on the
!                screen.  This is a version independant function, which will
!                place the cursor by characters in v5/8 or v6.
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
[ LocateCursor y x;
#ifdef TARGET_ZCODE;
if (strict && 0==x or y) return;
#Ifdef V6DEFS_H;
 StatusWin.SetCursorByChar(y,x);
#Ifnot;
 @set_cursor y x;
#Endif;
#ifnot;
glk_window_move_cursor(gg_statuswin,x-1,y-1);
#endif;

];
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
! DaemonRunning - Returns TRUE if the object specified is currently running
!                 a daemon
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
[ DaemonRunning x i;
  for (i=0:i<active_timers:i++)
      if (the_timers-->i == $8000 + x)
          rtrue;
  rfalse;
];
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
! TimerRunning - Returns TRUE if the object specified is currently running
!                 a timer
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
[ TimerRunning x i;
  for (i=0:i<active_timers:i++)
      if (the_timers-->i ==x)
          rtrue;
  rfalse;
];

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
! Abs - Returns the absolute value of a number
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
[ abs x;
 if (x<0) return -x;
 else return x;
];
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
! Boldit - prints a string in bold
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
[ Boldit x;
Emphasis(1);
print (string) x;
Emphasis(0);
];

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
! Pow(x,y) - returns x^y
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
[ pow x y z;
z=1;
while(y>0)
{z=z*x;
 y--;
}
return z;
];

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
! get_window_from_stream - returns the window with which a stream is
!                       associated (suitable only for finding the
!                       "current" window)
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
ifdef TARGET_GLULX;
[ get_window_from_stream str i;
i=0;
i=glk_window_iterate(i,gg_arguments);
while(i)
{
 if (str == glk_window_get_stream(i))
  return i;
 i=glk_window_iterate(i,gg_arguments);
}
return 0;
];
endif;

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
! sinsert(x,y,comp) - Inserts x into y in sorted position. Comp is a function
!               which takes two arguments, and returns <, >, or =  zero
!               if the first object goes before, after, or at the same point
!               in the sorting order as the second.
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
[ sinsert x y func o i l;
objectloop(o in y)
{
 i=func(x,o);
 if (i>0) break;
 l=o;
}
if (o==nothing) ! o is the last one, x goes after it, or
 pmove(x,y);
else if (l<=0) ! it goes before the first one
 move x to y;
else
 rmove(x,l);
];

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
! ScriptPrint - Print to the transcript; if scripting is enabled, print
!       x to the transcript. if x is a function, a second parameter will be
!       passed to it.
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
#ifdef TARGET_ZCODE;
[ ScriptPrint x y;
if (transcript_mode)
{
@output_stream -1;
if (x ofclass string) print (string) x;
else x(y);
@output_stream 1;
}
];
ifnot;
[ ScriptPrint x y z;
if (gg_scriptstr)
{
 z=glk_stream_get_current();
 glk_stream_set_current(gg_scriptstr);
 PrintAnything(x,y);
 glk_stream_set_current(z);
}
];
endif;
endif;