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.2 2003/06/17 04:25:24 dillon Exp $ 6 */ 7 8 #include <string.h> 9 #include "include.h" 10 11 /************************************************************************ 12 / 13 / FUNCTION NAME: getstring() 14 / 15 / FUNCTION: read a string from operator 16 / 17 / AUTHOR: E. A. Estes, 12/4/85 18 / 19 / ARGUMENTS: 20 / char *cp - pointer to buffer area to fill 21 / int mx - maximum number of characters to put in buffer 22 / 23 / RETURN VALUE: none 24 / 25 / MODULES CALLED: wmove(), _filbuf(), clearok(), waddstr(), wrefresh(), 26 / wclrtoeol() 27 / 28 / GLOBAL INPUTS: Echo, _iob[], Wizard, *stdscr 29 / 30 / GLOBAL OUTPUTS: _iob[] 31 / 32 / DESCRIPTION: 33 / Read a string from the keyboard. 34 / This routine is specially designed to: 35 / 36 / - strip non-printing characters (unless Wizard) 37 / - echo, if desired 38 / - redraw the screen if CH_REDRAW is entered 39 / - read in only 'mx - 1' characters or less characters 40 / - nul-terminate string, and throw away newline 41 / 42 / 'mx' is assumed to be at least 2. 43 / 44 *************************************************************************/ 45 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 { 71 case CH_ERASE: /* back up one character */ 72 if (inptr > cp) 73 --inptr; 74 break; 75 76 case CH_KILL: /* back up to original location */ 77 inptr = cp; 78 break; 79 80 case CH_NEWLINE: /* terminate string */ 81 break; 82 83 case CH_REDRAW: /* redraw screen */ 84 clearok(stdscr, TRUE); 85 continue; 86 87 default: /* put data in string */ 88 if (ch >= ' ' || Wizard) 89 /* printing char; put in string */ 90 *inptr++ = ch; 91 } 92 93 *inptr = '\0'; /* terminate string */ 94 } 95 while (ch != CH_NEWLINE && inptr < cp + mx); 96 } 97 /**/ 98 /************************************************************************ 99 / 100 / FUNCTION NAME: more() 101 / 102 / FUNCTION: pause and prompt player 103 / 104 / AUTHOR: E. A. Estes, 12/4/85 105 / 106 / ARGUMENTS: 107 / int where - line on screen on which to pause 108 / 109 / RETURN VALUE: none 110 / 111 / MODULES CALLED: wmove(), waddstr(), getanswer() 112 / 113 / GLOBAL INPUTS: *stdscr 114 / 115 / GLOBAL OUTPUTS: none 116 / 117 / DESCRIPTION: 118 / Print a message, and wait for a space character. 119 / 120 *************************************************************************/ 121 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 inputoption() 193 { 194 ++Player.p_age; /* increase age */ 195 196 if (Player.p_ring.ring_type != R_SPOILED) 197 /* ring ok */ 198 return(getanswer("T ", TRUE)); 199 else 200 /* bad ring */ 201 { 202 getanswer(" ", TRUE); 203 return((int) ROLL(0.0, 5.0) + '0'); 204 } 205 } 206 /**/ 207 /************************************************************************ 208 / 209 / FUNCTION NAME: interrupt() 210 / 211 / FUNCTION: handle interrupt from operator 212 / 213 / AUTHOR: E. A. Estes, 12/4/85 214 / 215 / ARGUMENTS: none 216 / 217 / RETURN VALUE: none 218 / 219 / MODULES CALLED: fork(), exit(), wait(), death(), alarm(), execl(), wmove(), 220 / getgid(), signal(), getenv(), wclear(), setuid(), getuid(), setgid(), 221 / crmode(), clearok(), waddstr(), cleanup(), wrefresh(), leavegame(), 222 / 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 interrupt() 236 { 237 char line[81]; /* a place to store data already on screen */ 238 int loop; /* counter */ 239 int x, y; /* coordinates on screen */ 240 int ch; /* input */ 241 unsigned savealarm; /* to save alarm value */ 242 243 #ifdef SYS3 244 signal(SIGINT, SIG_IGN); 245 #endif 246 #ifdef SYS5 247 signal(SIGINT, SIG_IGN); 248 #endif 249 250 savealarm = alarm(0); /* turn off any alarms */ 251 252 getyx(stdscr, y, x); /* save cursor location */ 253 254 for (loop = 0; loop < 80; ++loop) /* save line on screen */ 255 { 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 } 270 else 271 { 272 mvaddstr(4, 0, "Do you really want to quit ? "); 273 ch = getanswer("NY", FALSE); 274 if (ch == 'Y') 275 leavegame(); 276 /*NOTREACHED*/ 277 } 278 279 mvaddstr(4, 0, line); /* restore data on screen */ 280 move(y, x); /* restore cursor */ 281 refresh(); 282 283 #ifdef SYS3 284 signal(SIGINT, interrupt); 285 #endif 286 #ifdef SYS5 287 signal(SIGINT, interrupt); 288 #endif 289 290 alarm(savealarm); /* restore alarm */ 291 } 292 /**/ 293 /************************************************************************ 294 / 295 / FUNCTION NAME: getanswer() 296 / 297 / FUNCTION: get an answer from operator 298 / 299 / AUTHOR: E. A. Estes, 12/4/85 300 / 301 / ARGUMENTS: 302 / char *choices - string of (upper case) valid choices 303 / bool def - set if default answer 304 / 305 / RETURN VALUE: none 306 / 307 / MODULES CALLED: alarm(), wmove(), waddch(), signal(), setjmp(), strchr(), 308 / _filbuf(), clearok(), toupper(), wrefresh(), mvprintw(), wclrtoeol() 309 / 310 / GLOBAL INPUTS: catchalarm(), Echo, _iob[], _ctype[], *stdscr, Timeout, 311 / Timeoenv[] 312 / 313 / GLOBAL OUTPUTS: _iob[] 314 / 315 / DESCRIPTION: 316 / Get a single character answer from operator. 317 / Timeout waiting for response. If we timeout, or the 318 / answer in not in the list of valid choices, print choices, 319 / and wait again, otherwise return the first character in ths 320 / list of choices. 321 / Give up after 3 tries. 322 / 323 *************************************************************************/ 324 325 getanswer(choices, def) 326 char *choices; 327 bool def; 328 { 329 int ch; /* input */ 330 int loop; /* counter */ 331 int oldx, oldy; /* original coordinates on screen */ 332 333 getyx(stdscr, oldy, oldx); 334 alarm(0); /* make sure alarm is off */ 335 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 } 349 else 350 /* wait for response */ 351 { 352 clrtoeol(); 353 refresh(); 354 #ifdef BSD41 355 sigset(SIGALRM, catchalarm); 356 #else 357 signal(SIGALRM, catchalarm); 358 #endif 359 /* set timeout */ 360 if (Timeout) 361 alarm(7); /* short */ 362 else 363 alarm(600); /* long */ 364 365 ch = getchar(); 366 367 alarm(0); /* turn off timeout */ 368 369 if (ch < 0) 370 /* caught some signal */ 371 { 372 ++loop; 373 continue; 374 } 375 else if (ch == CH_REDRAW) 376 /* redraw screen */ 377 { 378 clearok(stdscr, TRUE); /* force clear screen */ 379 ++loop; /* don't count this input */ 380 continue; 381 } 382 else if (Echo) 383 { 384 addch(ch); /* echo character */ 385 refresh(); 386 } 387 388 if (islower(ch)) 389 /* convert to upper case */ 390 ch = toupper(ch); 391 392 if (def || strchr(choices, ch) != NULL) 393 /* valid choice */ 394 return(ch); 395 else if (!def && loop > 1) 396 /* bad choice; prompt, and try again */ 397 { 398 YELL: mvprintw(oldy + 1, 0, "Please choose one of : [%s]\n", choices); 399 move(oldy, oldx); 400 clrtoeol(); 401 continue; 402 } 403 else 404 /* return default answer */ 405 break; 406 } 407 } 408 409 return(*choices); 410 } 411 /**/ 412 /************************************************************************ 413 / 414 / FUNCTION NAME: catchalarm() 415 / 416 / FUNCTION: catch timer when waiting for input 417 / 418 / AUTHOR: E. A. Estes, 12/4/85 419 / 420 / ARGUMENTS: none 421 / 422 / RETURN VALUE: none 423 / 424 / MODULES CALLED: longjmp() 425 / 426 / GLOBAL INPUTS: Timeoenv[] 427 / 428 / GLOBAL OUTPUTS: none 429 / 430 / DESCRIPTION: 431 / Come here when the alarm expires while waiting for input. 432 / Simply longjmp() into getanswer(). 433 / 434 *************************************************************************/ 435 436 void 437 catchalarm() 438 { 439 longjmp(Timeoenv, 1); 440 } 441