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