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