/*
MYLIB2.C

These routines are CONDITIONALLY compiled; i.e., only as needed.

----------------------------------------------------------------------
Incorporates special mods used by my Backgammon game, BACKGMMN.C etc.
----------------------------------------------------------------------

A set of common I/O functions that seem to turn up a lot in my programs, 
including terminal functions for Kaypro 10, 4'84, 2X etc.

Uses Software Toolworks' C/80 3.1 compiler.  Place #include "mylib2.c" at the
end of your source file for correct CONDITIONAL COMPILATION. 

David C. Oshel
1219 Harding Ave.
Ames, Iowa 50010

Last modified:  March 25, 1986

-----------------------------------------------------------------------------
** WARNING ** These routines use direct console IO, bdos function 6!

         YOU MUST CALL INIT_LIB() BEFORE USING THESE ROUTINES!

                      ======= UTILITIES =======

 * init_lib()		- CALL THIS FIRST, OR THE RESULT WILL BE VERY STRANGE!
 *
 * puts(p)		- unformatted print, e.g., puts("Hello, sailor!\n");
 * gets(p,max)		- printable input only, no prompt character
 *
 * ask(p)		- demand Yes or No response to question p
 * random()		- effective random 16-bit integer IFF gets() is used
 * sleep(n)		- sleep n/10ths of a second, roughly (from C80.LIB)
 * rollup()		- roll up 23 lines of screen
 * ONscript()		- printer echo ON  for output via puts, chrout
 * OFFscript()		- printer echo OFF for output via puts, chrout
 * ONinterrupt()	- Ctl-C, Ctl-B cause program exit
 * OFFinterrupt()	- Ctl-C, Ctl-B cause comedy
 * hide_input(p,max)	- like gets, but used when entering passwords
 * chrout(c)		- if scripting, echo output also to LST:
 * putscreen(p)		- like puts, but always and only to screen


           ======= KAYPRO 10 TERMINAL/VIDEO FUNCTIONS =======

 * gotoxy(x,y)		- 0,0 is top left, horz <= 79 precedes vert <= 24,
 *                        where 0,24 is on the 25th, status, line.
 * beep()		- terminal bell
 * home()		- home cursor, do not clear screen
 * clr_screen()		- home and clear
 *
 * shadow_box(h,v,x1,y1,x2,y2) - like box, but with shadow, calls box
 * box(tlx,tly,brx,bry) - draw a line box, coords: topleft XY, bottomright XY
 *			  note that box calls ldraw(x1,y1,x2,y2), below
 *
 * clr_lend()		- clear from cursor to end of line
 * clr_send()		- clear from cursor to end of screen
 * rev_vid(),
 * nor_vid()		- reverse field 
 * dim_vid(),
 * bri_vid()		- low/high intensity
 * on_blink(),
 * off_blink()		- blinking chars
 * ul_start(),
 * ul_stop()		- start/stop underline
 * save_cursor(),
 * retn_cursor()	- remember/restore current cursor location
 * ins_line(),
 * del_line()		- insert/delete screen text line
 * on_cursor(),
 * off_cursor()		- hide/show cursor
 * vm_on(),
 * vm_off()		- "Video Mode" commands
 * pixel(x,y)		- draw pixel at x,y (video coords, x <= 159, y <= 99)
 * no_pixel(x,y)	- erase pixel at x,y
 * ldraw(x1,y1,x2,y2)  	- draw/ erase graphics line, see discussion for box
 * lwipe(x1,y1,x2,y2)	- range for video coordinates as for pixel
*/


#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif


/* hide this here so's not to worry about it elsewhere */
/* "printf.c" collides with one of these, can't remember which */
/* puts() takes longer to write, but executes faster */
extern char Cmode, IOpread[4], IOpwrit[4], IOpeof[4];

/* make these known only to what follows */
static int MYbstout, MYscrtp, MYretnirp; /* odd names mark semi-private   */
static unsigned RNDloc; /* effective random location, bumped by gets()    */
			/* and scrambled when the LCG random() is called  */
			/* makes a decent algorithm for interactive games */


#ifneed init_lib
init_lib() {

	MYretnirp = fopen("LST:","w");
	OFFscript();
	ONinterrupt();
	Cmode = 0;
	IOpread[0] = 6; IOpwrit[0] = 6;

} /* end: init_lib */
#endif



 
#ifneed random
random() {  	/* depends on effective random location spun by gets() */

	RNDloc = 2053 * RNDloc + 13849;
	return (RNDloc);
}
#endif



#ifneed ONscript
ONscript() {

	MYscrtp = TRUE; 

}
#endif
#ifneed OFFscript
OFFscript() {

	MYscrtp = FALSE; 

}
#endif


#ifneed ONinterrupt
ONinterrupt() {

	MYbstout = TRUE;

}
#endif
#ifneed OFFinterrupt
OFFinterrupt() {

	MYbstout = FALSE;

}
#endif


#ifneed ask
ask(p) char *p; {

char ch, resp[2];

loo:	puts(p);
	gets(resp,1);
	ch = toupper( *resp );
	if ( !( ch == 'Y' || ch == 'N' )) {
		puts("Please answer the question, Yes or No.\n");
		goto loo;
	}
	return (ch == 'Y');

} /* end: ask */
#endif


#ifneed rollup
rollup() {

int i;

	for (i=0; i<23; i++) puts("\n");

} /* end: rollup */ 
#endif


#ifneed sleep
sleep( n )  int n;  {		/* sleep for n/10 seconds, 0 <= n < 256 */

	n;			/* get n into HL */
#asm
	MOV	B,L		;delay B/10ths of a second
__DL0:	MVI	A,100		;100 milliseconds, 1/10 second
__DL1:	MVI	C,249		;1 millisecond per unit of A at 4 MHz
__DL2:	DCR	C		;Leventhal, Z80 Assembly Language Programming
	JNZ	__DL2
	DCR	A
	JNZ	__DL1
	DCR	B
	JNZ	__DL0		;on exit, HL has FALSE if n was 0, else TRUE
#endasm
} /* end: sleep */
#endif


/*========================================*/
/*  GETS(p, maxinput)                     */
/*  Local getline function with special   *---* WARNING:                    */
/*  input handling,  1 <= len <= maxinput *---* Execute INIT_LIB() first !! */
/*  Updates effective random, RNDloc,     */
/*  Forces input from CONSOLE only!       */
/*========================================*/ 

#ifneed gets
gets(p,maxinput) char *p; int maxinput; {

/* This function depends on BDOS Function #6.  Init_lib() sets Cmode=0 and
   IOpread[0]=6 and IOpwrit[0]=6 (courtesy of and peculiar to C/80 3.1)
   YOU must ensure that the target string is long enough to collect the
   entire maximum input allowed and specified, INCLUDING FINAL NULL!    */

static int len;
static char ch;

	len = -1;
	if (maxinput < 1 || maxinput > 127) maxinput = 79;

        /*--------------------------------*/
        /* SPECIAL ROUTINE FOR BACKGAMMON */
        /*--------------------------------*/

loo:	while ( !(ch = getc(0)) ) acg(); /* keep the game lively */

	if (len < 0) len = 0;	/* don't destroy prompt by backing up */
	if (ch == '\n') {  	/* end of line?  don't store newline */
		*p = '\0';	/* mark it with a B for baby and me */
		/* chrout('\n'); */ /* but DON'T echo newline */
		return ( len ); /* <--- HERE IS THE FUNCTION EXIT! */
	}
	else if (ch == '\b' || ch == 0x7F) {  	/* backspace? rubout? */
		if (len--) {			/* where's the prompt?  */
			puts("\008 \008");	/* we're ok, echo erase */
			p--;			/* delete from string */
		}
	}

        /*--------------------------------*/
        /* SPECIAL ROUTINE FOR BACKGAMMON */
        /*--------------------------------*/

	else if (ch == '\003') {  /* user bailout key is Ctrl-C, not ESC */
		if (MYbstout) exit();
		else {
                     haltgame(); /* sets whofirst flag and does jumpjack() */
		}
	}

	else if (ch == '\025' || ch == '\030') {  /* Ctl-U, Ctl-X */
		while (len--) {
			p--;
			puts("\008 \008");
		}
	}
	else if (len == maxinput) { /* test specials before testing len */
		chrout('\007');
	}
	else if (ch > 31 && ch < 127) { /* printable char? */
		chrout(ch);		/* yes, echo it */
		*p++ = ch;		/* collect it */
		len++;			/* keep track of it */
	}
	else {  			/* control chars? */
		chrout('\007');
	}		
	goto loo;

} /* end: gets */
#endif




#ifneed hide_input
hide_input(s,len) char *s; int len; {

/* receive at most len chars in s buffer, 
   terminate string with zero, 
   but echo each char with 1, 2, or 3 meaningless dots */

char ch; int num;

	if ((len < 1) || (len > 127)) len = 127;
	num = 0;
	for (;;) { /* forever */ 
	while ((ch = getc(0)) == 0) /* bdos 6 does not wait, so we do */
	;
	if ((ch == '\r') || (ch == '\n') || (num++ > len)) { 
		/* not sure what the CR key actually is to bdos 6 & C/80 */
		*s++ = '\0';
		return;  /* this way out */
	}
	if ((num % 2) == 0) putc('.',0); /* deception, illusion */
	if ((num % 5) == 0) putc('.',0);
	putc('.',0);
	*s++ = ch;
	}

} /* end: hide_input */
#endif




/*------------------------ kpro stuff -------------------------*/

#ifneed shadow_box
/* like box, but with horizontal & vertical displacement for shadow */
shadow_box(h,v,x1,y1,x2,y2) int h,v,x1,y1,x2,y2;
{
	box(x1+h,y1+v,x2+h,y2+v);   /* draw the shadow  */
	box(x1,y1,x2,y2);	    /* draw the box     */
	ldraw(x1+h,y1+v,x1,y1);     /* draw the corners */
	ldraw(x2+h,y2+v,x2,y2);
	ldraw(x2+h,y1+v,x2,y1);
	ldraw(x1+h,y2+v,x1,y2);
}
#endif


#ifneed box
/* parameters are topleft X,Y and bottomright X,Y 
   X ranges from 0 to 159, Y ranges from 0 to 99, top left is 0,0
   */
box(x1,y1,x2,y2) int x1,y1,x2,y2; {
	ldraw(x1,y1,x1,y2);
	ldraw(x1,y2,x2,y2); /* appears to draw the box anticlockwise */ 
	ldraw(x2,y1,x2,y2);
	ldraw(x1,y1,x2,y1);
}
#endif



#ifneed gotoxy
gotoxy (xpos,ypos) int xpos,ypos; {  /* 0,0 is top left corner */
	putscreen("\033=");
	putc(ypos+' ',0);
	putc(xpos+' ',0);
	}
#endif


#ifneed beep
beep()		{ putc(7,0); } 	/* send bell character */
#endif

#ifneed home
home()		{ putc(30,0); }	/* home cursor to top left */
#endif

#ifneed clr_screen
clr_screen() 	{ putc(26,0); }	/* home and erase screen */
#endif


#ifneed clr_lend
clr_lend() 	{ putc(24,0); }	/* clear to end of line */
#endif

#ifneed clr_send
clr_send() 	{ putc(23,0); }	/* clear to end of screen */
#endif



#ifneed rev_vid
rev_vid() 	{ putscreen ("\033B0"); }	/* reverse background */
#endif

#ifneed nor_vid
nor_vid() 	{ putscreen ("\033C0"); }
#endif



#ifneed dim_vid
dim_vid() 	{ putscreen ("\033B1"); }	/* low intensity */
#endif

#ifneed bri_vid
bri_vid() 	{ putscreen ("\033C1"); }
#endif



#ifneed on_blink
on_blink()	{ putscreen ("\033B2"); }    /* blinking characters */
#endif

#ifneed off_blink
off_blink() 	{ putscreen ("\033C2"); }
#endif



#ifneed ul_start
ul_start() 	{ putscreen ("\033B3"); }	/* underline */
#endif

#ifneed ul_stop
ul_stop() 	{ putscreen ("\033C3"); }
#endif


#ifneed save_cursor
save_cursor()	{ putscreen ("\033B6"); }  /* remember cursor position */
#endif
#ifneed retn_cursor
retn_cursor()	{ putscreen ("\033C6"); }  /* return to remembered pos */
#endif


#ifneed on_status
on_status()	{ putscreen ("\033B7"); }    /* status line preservation on */
#endif
#ifneed off_status
off_status()	{ putscreen ("\033C7"); }
#endif


#ifneed ins_line
ins_line() {				/* insert text line */
	putscreen("\033R");
	}
#endif
#ifneed del_line
del_line() {				/* delete text line */
	putscreen("\033E");
	}
#endif


#ifneed on_cursor
on_cursor() 	{ putscreen ("\033B4"); }	/* (in)visible cursor */
#endif
#ifneed off_cursor
off_cursor() 	{ putscreen ("\033C4"); }
#endif



/* Video Mode ON/OFF: video WORD, 8 bit video if 15 and 7 are both high */
/*                    VM-ON 10000001 11111111 VM-OFF                    */
/*                          ^video ^x^video                             */
/* otherwise, video BYTE, high bit 7 interprets bits 0-6 as screen dots */
/*                    11111111                                          */
/*                    ^video                                            */
/* e.g.,                                                                */
/*        Non-VideoMode                 VideoMode                       */
/*    xx     1 11:0     where % is    1 01:0  1 11:0      xx            */
/*    xx     3 11 2     the video     3 00 2  3 11 2      xx            */
/*    xx     5 11 4     flag bit,     5 00 4  5 11 4      xx            */
/*     x     7:%1 6     x is pixel    7:%0 6  7:%1 6      xx            */
/*             ^                        ^       ^                       */
/* to set the pixels, first do a gotoxy to character screen position    */
/* this mode is faster than Pixel ON/OFF if values are drawn from table */
#ifneed vm_on
vm_on()		{ putscreen ("\033B5"); }	/* video mode on */
#endif
#ifneed vm_off
vm_off()	{ putscreen ("\033C5"); }
#endif


#ifneed pixel
pixel(x,y) int x,y; {			/* x <= 159, y <= 99 */
	putscreen("\033*");
	putc(y+' ',0); putc(x+' ',0);
}
#endif

#ifneed no_pixel
no_pixel(x,y) int x,y; {		/* x <= 159, y <= 99 */
	putscreen("\033 ");
	putc(y+' ',0); putc(x+' ',0);
}
#endif


#ifneed ldraw
/* use x1 <= x2, y1 <= y2, order is significant (Kaypro bug?) */
ldraw(x1,y1,x2,y2) int x1,x2,y1,y2; {	/* x <= 159, y <= 99 */
	putscreen("\033L");
	putc(y1+' ',0); putc(x1+' ',0); 
	putc(y2+' ',0); putc(x2+' ',0);
}
#endif


#ifneed lwipe
lwipe(x1,y1,x2,y2) int x1,x2,y1,y2; {	/* x <= 159, y <= 99 */
	putscreen("\033D");
	putc(y1+' ',0); putc(x1+' ',0); 
	putc(y2+' ',0); putc(x2+' ',0);
}
#endif


#ifneed putscreen
putscreen(p) char *p; {

	while (*p) putc(*p++,0);

} /* end: putscreen */
#endif


#ifneed puts
puts(p) char *p; {

	while (*p) chrout(*p++);

} /* end: puts */
#endif


#ifneed chrout
chrout(c) char c; {  /* SPECIAL FOR SCRIPT OPTION WITH LST: */

	putc(c,0);
	if ( MYscrtp ) putc(c,MYretnirp);

} /* end: chrout */
#endif

/* end: MYLIB.C */

