Home | History | Annotate | Line # | Download | only in phantasia
io.c revision 1.2
      1 /*	$NetBSD: io.c,v 1.2 1995/03/24 03:58:50 cgd Exp $	*/
      2 
      3 /*
      4  * io.c - input/output routines for Phantasia
      5  */
      6 
      7 #include "include.h"
      8 
      9 /************************************************************************
     10 /
     11 / FUNCTION NAME: getstring()
     12 /
     13 / FUNCTION: read a string from operator
     14 /
     15 / AUTHOR: E. A. Estes, 12/4/85
     16 /
     17 / ARGUMENTS:
     18 /	char *cp - pointer to buffer area to fill
     19 /	int mx - maximum number of characters to put in buffer
     20 /
     21 / RETURN VALUE: none
     22 /
     23 / MODULES CALLED: wmove(), _filbuf(), clearok(), waddstr(), wrefresh(),
     24 /	wclrtoeol()
     25 /
     26 / GLOBAL INPUTS: Echo, _iob[], Wizard, *stdscr
     27 /
     28 / GLOBAL OUTPUTS: _iob[]
     29 /
     30 / DESCRIPTION:
     31 /	Read a string from the keyboard.
     32 /	This routine is specially designed to:
     33 /
     34 /	    - strip non-printing characters (unless Wizard)
     35 /	    - echo, if desired
     36 /	    - redraw the screen if CH_REDRAW is entered
     37 /	    - read in only 'mx - 1' characters or less characters
     38 /	    - nul-terminate string, and throw away newline
     39 /
     40 /	'mx' is assumed to be at least 2.
     41 /
     42 /************************************************************************/
     43 
     44 getstring(cp, mx)
     45 register char	*cp;
     46 register int	mx;
     47 {
     48 register char	*inptr;		/* pointer into string for next string */
     49 int	x, y;			/* original x, y coordinates on screen */
     50 int	ch;			/* input */
     51 
     52     getyx(stdscr, y, x);	/* get coordinates on screen */
     53     inptr = cp;
     54     *inptr = '\0';		/* clear string to start */
     55     --mx;			/* reserve room in string for nul terminator */
     56 
     57     do
     58 	/* get characters and process */
     59 	{
     60 	if (Echo)
     61 	    mvaddstr(y, x, cp);	/* print string on screen */
     62 	clrtoeol();		/* clear any data after string */
     63 	refresh();		/* update screen */
     64 
     65 	ch = getchar();		/* get character */
     66 
     67 	switch (ch)
     68 	    {
     69 	    case CH_ERASE:	/* back up one character */
     70 		if (inptr > cp)
     71 		    --inptr;
     72 		break;
     73 
     74 	    case CH_KILL:	/* back up to original location */
     75 		inptr = cp;
     76 		break;
     77 
     78 	    case CH_NEWLINE:	/* terminate string */
     79 		break;
     80 
     81 	    case CH_REDRAW:	/* redraw screen */
     82 		clearok(stdscr, TRUE);
     83 		continue;
     84 
     85 	    default:		/* put data in string */
     86 		if (ch >= ' ' || Wizard)
     87 		    /* printing char; put in string */
     88 		    *inptr++ = ch;
     89 	    }
     90 
     91 	*inptr = '\0';		/* terminate string */
     92 	}
     93     while (ch != CH_NEWLINE && inptr < cp + mx);
     94 }
     95 /**/
     97 /************************************************************************
     98 /
     99 / FUNCTION NAME: more()
    100 /
    101 / FUNCTION: pause and prompt player
    102 /
    103 / AUTHOR: E. A. Estes, 12/4/85
    104 /
    105 / ARGUMENTS:
    106 /	int where - line on screen on which to pause
    107 /
    108 / RETURN VALUE: none
    109 /
    110 / MODULES CALLED: wmove(), waddstr(), getanswer()
    111 /
    112 / GLOBAL INPUTS: *stdscr
    113 /
    114 / GLOBAL OUTPUTS: none
    115 /
    116 / DESCRIPTION:
    117 /	Print a message, and wait for a space character.
    118 /
    119 /************************************************************************/
    120 
    121 more(where)
    122 int	where;
    123 {
    124     mvaddstr(where, 0, "-- more --");
    125     getanswer(" ", FALSE);
    126 }
    127 /**/
    129 /************************************************************************
    130 /
    131 / FUNCTION NAME: infloat()
    132 /
    133 / FUNCTION: input a floating point number from operator
    134 /
    135 / AUTHOR: E. A. Estes, 12/4/85
    136 /
    137 / ARGUMENTS: none
    138 /
    139 / RETURN VALUE: floating point number from operator
    140 /
    141 / MODULES CALLED: sscanf(), getstring()
    142 /
    143 / GLOBAL INPUTS: Databuf[]
    144 /
    145 / GLOBAL OUTPUTS: none
    146 /
    147 / DESCRIPTION:
    148 /	Read a string from player, and scan for a floating point
    149 /	number.
    150 /	If no valid number is found, return 0.0.
    151 /
    152 /************************************************************************/
    153 
    154 double
    155 infloat()
    156 {
    157 double	result;		/* return value */
    158 
    159     getstring(Databuf, SZ_DATABUF);
    160     if (sscanf(Databuf, "%lf", &result) < 1)
    161 	/* no valid number entered */
    162 	result = 0.0;
    163 
    164     return(result);
    165 }
    166 /**/
    168 /************************************************************************
    169 /
    170 / FUNCTION NAME: inputoption()
    171 /
    172 / FUNCTION: input an option value from player
    173 /
    174 / AUTHOR: E. A. Estes, 12/4/85
    175 /
    176 / ARGUMENTS: none
    177 /
    178 / RETURN VALUE: none
    179 /
    180 / MODULES CALLED: floor(), drandom(), getanswer()
    181 /
    182 / GLOBAL INPUTS: Player
    183 /
    184 / GLOBAL OUTPUTS: Player
    185 /
    186 / DESCRIPTION:
    187 /	Age increases with every move.
    188 /	Refresh screen, and get a single character option from player.
    189 /	Return a random value if player's ring has gone bad.
    190 /
    191 /************************************************************************/
    192 
    193 inputoption()
    194 {
    195     ++Player.p_age;		/* increase age */
    196 
    197     if (Player.p_ring.ring_type != R_SPOILED)
    198 	/* ring ok */
    199 	return(getanswer("T ", TRUE));
    200     else
    201 	/* bad ring */
    202 	{
    203 	getanswer(" ", TRUE);
    204 	return((int) ROLL(0.0, 5.0) + '0');
    205 	}
    206 }
    207 /**/
    209 /************************************************************************
    210 /
    211 / FUNCTION NAME: interrupt()
    212 /
    213 / FUNCTION: handle interrupt from operator
    214 /
    215 / AUTHOR: E. A. Estes, 12/4/85
    216 /
    217 / ARGUMENTS: none
    218 /
    219 / RETURN VALUE: none
    220 /
    221 / MODULES CALLED: fork(), exit(), wait(), death(), alarm(), execl(), wmove(),
    222 /	getgid(), signal(), getenv(), wclear(), setuid(), getuid(), setgid(),
    223 /	crmode(), clearok(), waddstr(), cleanup(), wrefresh(), leavegame(),
    224 /	getanswer()
    225 /
    226 / GLOBAL INPUTS: Player, *stdscr
    227 /
    228 / GLOBAL OUTPUTS: none
    229 /
    230 / DESCRIPTION:
    231 /	Allow player to quit upon hitting the interrupt key.
    232 /	If the player wants to quit while in battle, he/she automatically
    233 /	dies.
    234 /
    235 /************************************************************************/
    236 
    237 interrupt()
    238 {
    239 char	line[81];		/* a place to store data already on screen */
    240 register int	loop;		/* counter */
    241 int	x, y;			/* coordinates on screen */
    242 int	ch;			/* input */
    243 unsigned	savealarm;	/* to save alarm value */
    244 
    245 #ifdef SYS3
    246     signal(SIGINT, SIG_IGN);
    247 #endif
    248 #ifdef SYS5
    249     signal(SIGINT, SIG_IGN);
    250 #endif
    251 
    252     savealarm = alarm(0);		/* turn off any alarms */
    253 
    254     getyx(stdscr, y, x);		/* save cursor location */
    255 
    256     for (loop = 0; loop < 80; ++loop)	/* save line on screen */
    257 	{
    258 	move(4, loop);
    259 	line[loop] = inch();
    260 	}
    261     line[80] = '\0';			/* nul terminate */
    262 
    263     if (Player.p_status == S_INBATTLE || Player.p_status == S_MONSTER)
    264 	/* in midst of fighting */
    265 	{
    266 	mvaddstr(4, 0, "Quitting now will automatically kill your character.  Still want to ? ");
    267 	ch = getanswer("NY", FALSE);
    268 	if (ch == 'Y')
    269 	    death("Bailing out");
    270 	    /*NOTREACHED*/
    271 	}
    272     else
    273 	{
    274 	mvaddstr(4, 0, "Do you really want to quit ? ");
    275 	ch = getanswer("NY", FALSE);
    276 	if (ch == 'Y')
    277 	    leavegame();
    278 	    /*NOTREACHED*/
    279 	}
    280 
    281     mvaddstr(4, 0, line); 		/* restore data on screen */
    282     move(y, x);				/* restore cursor */
    283     refresh();
    284 
    285 #ifdef SYS3
    286     signal(SIGINT, interrupt);
    287 #endif
    288 #ifdef SYS5
    289     signal(SIGINT, interrupt);
    290 #endif
    291 
    292     alarm(savealarm);			/* restore alarm */
    293 }
    294 /**/
    296 /************************************************************************
    297 /
    298 / FUNCTION NAME: getanswer()
    299 /
    300 / FUNCTION: get an answer from operator
    301 /
    302 / AUTHOR: E. A. Estes, 12/4/85
    303 /
    304 / ARGUMENTS:
    305 /	char *choices - string of (upper case) valid choices
    306 /	bool def - set if default answer
    307 /
    308 / RETURN VALUE: none
    309 /
    310 / MODULES CALLED: alarm(), wmove(), waddch(), signal(), setjmp(), strchr(),
    311 /	_filbuf(), clearok(), toupper(), wrefresh(), mvprintw(), wclrtoeol()
    312 /
    313 / GLOBAL INPUTS: catchalarm(), Echo, _iob[], _ctype[], *stdscr, Timeout,
    314 /	Timeoenv[]
    315 /
    316 / GLOBAL OUTPUTS: _iob[]
    317 /
    318 / DESCRIPTION:
    319 /	Get a single character answer from operator.
    320 /	Timeout waiting for response.  If we timeout, or the
    321 /	answer in not in the list of valid choices, print choices,
    322 /	and wait again, otherwise return the first character in ths
    323 /	list of choices.
    324 /	Give up after 3 tries.
    325 /
    326 /************************************************************************/
    327 
    328 getanswer(choices, def)
    329 char	*choices;
    330 bool	def;
    331 {
    332 int	ch;			/* input */
    333 int	loop;			/* counter */
    334 int	oldx, oldy;		/* original coordinates on screen */
    335 
    336     getyx(stdscr, oldy, oldx);
    337     alarm(0);				/* make sure alarm is off */
    338 
    339     for (loop = 3; loop; --loop)
    340 	/* try for 3 times */
    341 	{
    342 	if (setjmp(Timeoenv) != 0)
    343 	    /* timed out waiting for response */
    344 	    {
    345 	    if (def || loop <= 1)
    346 		/* return default answer */
    347 		break;
    348 	    else
    349 		/* prompt, and try again */
    350 		goto YELL;
    351 	    }
    352 	else
    353 	    /* wait for response */
    354 	    {
    355 	    clrtoeol();
    356 	    refresh();
    357 #ifdef BSD41
    358 	    sigset(SIGALRM, catchalarm);
    359 #else
    360 	    signal(SIGALRM, catchalarm);
    361 #endif
    362 	    /* set timeout */
    363 	    if (Timeout)
    364 		alarm(7);		/* short */
    365 	    else
    366 		alarm(600);		/* long */
    367 
    368 	    ch = getchar();
    369 
    370 	    alarm(0);			/* turn off timeout */
    371 
    372 	    if (ch < 0)
    373 		/* caught some signal */
    374 		{
    375 		++loop;
    376 		continue;
    377 		}
    378 	    else if (ch == CH_REDRAW)
    379 		/* redraw screen */
    380 		{
    381 		clearok(stdscr, TRUE);	/* force clear screen */
    382 		++loop;			/* don't count this input */
    383 		continue;
    384 		}
    385 	    else if (Echo)
    386 		{
    387 		addch(ch);		/* echo character */
    388 		refresh();
    389 		}
    390 
    391 	    if (islower(ch))
    392 		/* convert to upper case */
    393 		ch = toupper(ch);
    394 
    395 	    if (def || strchr(choices, ch) != NULL)
    396 		/* valid choice */
    397 		return(ch);
    398 	    else if (!def && loop > 1)
    399 		/* bad choice; prompt, and try again */
    400 		{
    401 YELL:		mvprintw(oldy + 1, 0, "Please choose one of : [%s]\n", choices);
    402 		move(oldy, oldx);
    403 		clrtoeol();
    404 		continue;
    405 		}
    406 	    else
    407 		/* return default answer */
    408 		break;
    409 	    }
    410 	}
    411 
    412     return(*choices);
    413 }
    414 /**/
    416 /************************************************************************
    417 /
    418 / FUNCTION NAME: catchalarm()
    419 /
    420 / FUNCTION: catch timer when waiting for input
    421 /
    422 / AUTHOR: E. A. Estes, 12/4/85
    423 /
    424 / ARGUMENTS: none
    425 /
    426 / RETURN VALUE: none
    427 /
    428 / MODULES CALLED: longjmp()
    429 /
    430 / GLOBAL INPUTS: Timeoenv[]
    431 /
    432 / GLOBAL OUTPUTS: none
    433 /
    434 / DESCRIPTION:
    435 /	Come here when the alarm expires while waiting for input.
    436 /	Simply longjmp() into getanswer().
    437 /
    438 /************************************************************************/
    439 
    440 void
    441 catchalarm()
    442 {
    443     longjmp(Timeoenv, 1);
    444 }
    445