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