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