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 / 229 /************************************************************************/ 230 231 interrupt() 232 { 233 char line[81]; /* a place to store data already on screen */ 234 register int loop; /* counter */ 235 int x, y; /* coordinates on screen */ 236 int ch; /* input */ 237 unsigned savealarm; /* to save alarm value */ 238 239 #ifdef SYS3 240 signal(SIGINT, SIG_IGN); 241 #endif 242 #ifdef SYS5 243 signal(SIGINT, SIG_IGN); 244 #endif 245 246 savealarm = alarm(0); /* turn off any alarms */ 247 248 getyx(stdscr, y, x); /* save cursor location */ 249 250 for (loop = 0; loop < 80; ++loop) /* save line on screen */ 251 { 252 move(4, loop); 253 line[loop] = inch(); 254 } 255 line[80] = '\0'; /* nul terminate */ 256 257 if (Player.p_status == S_INBATTLE || Player.p_status == S_MONSTER) 258 /* in midst of fighting */ 259 { 260 mvaddstr(4, 0, "Quitting now will automatically kill your character. Still want to ? "); 261 ch = getanswer("NY", FALSE); 262 if (ch == 'Y') 263 death("Bailing out"); 264 /*NOTREACHED*/ 265 } 266 else 267 { 268 mvaddstr(4, 0, "Do you really want to quit ? "); 269 ch = getanswer("NY", FALSE); 270 if (ch == 'Y') 271 leavegame(); 272 /*NOTREACHED*/ 273 } 274 275 mvaddstr(4, 0, line); /* restore data on screen */ 276 move(y, x); /* restore cursor */ 277 refresh(); 278 279 #ifdef SYS3 280 signal(SIGINT, interrupt); 281 #endif 282 #ifdef SYS5 283 signal(SIGINT, interrupt); 284 #endif 285 286 alarm(savealarm); /* restore alarm */ 287 } 288 /**/ 289 /************************************************************************ 290 / 291 / FUNCTION NAME: getanswer() 292 / 293 / FUNCTION: get an answer from operator 294 / 295 / AUTHOR: E. A. Estes, 12/4/85 296 / 297 / ARGUMENTS: 298 / char *choices - string of (upper case) valid choices 299 / bool def - set if default answer 300 / 301 / RETURN VALUE: none 302 / 303 / MODULES CALLED: alarm(), wmove(), waddch(), signal(), setjmp(), strchr(), 304 / _filbuf(), clearok(), toupper(), wrefresh(), mvprintw(), wclrtoeol() 305 / 306 / GLOBAL INPUTS: catchalarm(), Echo, _iob[], _ctype[], *stdscr, Timeout, 307 / Timeoenv[] 308 / 309 / GLOBAL OUTPUTS: _iob[] 310 / 311 / DESCRIPTION: 312 / Get a single character answer from operator. 313 / Timeout waiting for response. If we timeout, or the 314 / answer in not in the list of valid choices, print choices, 315 / and wait again, otherwise return the first character in ths 316 / list of choices. 317 / Give up after 3 tries. 318 / 319 /************************************************************************/ 320 321 getanswer(choices, def) 322 char *choices; 323 bool def; 324 { 325 int ch; /* input */ 326 int loop; /* counter */ 327 int oldx, oldy; /* original coordinates on screen */ 328 329 getyx(stdscr, oldy, oldx); 330 alarm(0); /* make sure alarm is off */ 331 332 for (loop = 3; loop; --loop) 333 /* try for 3 times */ 334 { 335 if (setjmp(Timeoenv) != 0) 336 /* timed out waiting for response */ 337 { 338 if (def || loop <= 1) 339 /* return default answer */ 340 break; 341 else 342 /* prompt, and try again */ 343 goto YELL; 344 } 345 else 346 /* wait for response */ 347 { 348 clrtoeol(); 349 refresh(); 350 #ifdef BSD41 351 sigset(SIGALRM, catchalarm); 352 #else 353 signal(SIGALRM, catchalarm); 354 #endif 355 /* set timeout */ 356 if (Timeout) 357 alarm(7); /* short */ 358 else 359 alarm(600); /* long */ 360 361 ch = getchar(); 362 363 alarm(0); /* turn off timeout */ 364 365 if (ch < 0) 366 /* caught some signal */ 367 { 368 ++loop; 369 continue; 370 } 371 else if (ch == CH_REDRAW) 372 /* redraw screen */ 373 { 374 clearok(stdscr, TRUE); /* force clear screen */ 375 ++loop; /* don't count this input */ 376 continue; 377 } 378 else if (Echo) 379 { 380 addch(ch); /* echo character */ 381 refresh(); 382 } 383 384 if (islower(ch)) 385 /* convert to upper case */ 386 ch = toupper(ch); 387 388 if (def || strchr(choices, ch) != NULL) 389 /* valid choice */ 390 return(ch); 391 else if (!def && loop > 1) 392 /* bad choice; prompt, and try again */ 393 { 394 YELL: mvprintw(oldy + 1, 0, "Please choose one of : [%s]\n", choices); 395 move(oldy, oldx); 396 clrtoeol(); 397 continue; 398 } 399 else 400 /* return default answer */ 401 break; 402 } 403 } 404 405 return(*choices); 406 } 407 /**/ 408 /************************************************************************ 409 / 410 / FUNCTION NAME: catchalarm() 411 / 412 / FUNCTION: catch timer when waiting for input 413 / 414 / AUTHOR: E. A. Estes, 12/4/85 415 / 416 / ARGUMENTS: none 417 / 418 / RETURN VALUE: none 419 / 420 / MODULES CALLED: longjmp() 421 / 422 / GLOBAL INPUTS: Timeoenv[] 423 / 424 / GLOBAL OUTPUTS: none 425 / 426 / DESCRIPTION: 427 / Come here when the alarm expires while waiting for input. 428 / Simply longjmp() into getanswer(). 429 / 430 /************************************************************************/ 431 432 void 433 catchalarm() 434 { 435 longjmp(Timeoenv, 1); 436 } 437