134599Sbostic /* 234599Sbostic * io.c - input/output routines for Phantasia 334599Sbostic */ 434599Sbostic 534599Sbostic #include "include.h" 634599Sbostic 734599Sbostic /************************************************************************ 834599Sbostic / 934599Sbostic / FUNCTION NAME: getstring() 1034599Sbostic / 1134599Sbostic / FUNCTION: read a string from operator 1234599Sbostic / 1334599Sbostic / AUTHOR: E. A. Estes, 12/4/85 1434599Sbostic / 1534599Sbostic / ARGUMENTS: 1634599Sbostic / char *cp - pointer to buffer area to fill 1734599Sbostic / int mx - maximum number of characters to put in buffer 1834599Sbostic / 1934599Sbostic / RETURN VALUE: none 2034599Sbostic / 2134599Sbostic / MODULES CALLED: wmove(), _filbuf(), clearok(), waddstr(), wrefresh(), 2234599Sbostic / wclrtoeol() 2334599Sbostic / 2434599Sbostic / GLOBAL INPUTS: Echo, _iob[], Wizard, *stdscr 2534599Sbostic / 2634599Sbostic / GLOBAL OUTPUTS: _iob[] 2734599Sbostic / 2834599Sbostic / DESCRIPTION: 2934599Sbostic / Read a string from the keyboard. 3034599Sbostic / This routine is specially designed to: 3134599Sbostic / 3234599Sbostic / - strip non-printing characters (unless Wizard) 3334599Sbostic / - echo, if desired 3434599Sbostic / - redraw the screen if CH_REDRAW is entered 3534599Sbostic / - read in only 'mx - 1' characters or less characters 3634599Sbostic / - nul-terminate string, and throw away newline 3734599Sbostic / 3834599Sbostic / 'mx' is assumed to be at least 2. 3934599Sbostic / 4034599Sbostic /************************************************************************/ 4134599Sbostic 4234599Sbostic getstring(cp, mx) 4334599Sbostic register char *cp; 4434599Sbostic register int mx; 4534599Sbostic { 4634599Sbostic register char *inptr; /* pointer into string for next string */ 4734599Sbostic int x, y; /* original x, y coordinates on screen */ 4834599Sbostic int ch; /* input */ 4934599Sbostic 5034599Sbostic getyx(stdscr, y, x); /* get coordinates on screen */ 5134599Sbostic inptr = cp; 5234599Sbostic *inptr = '\0'; /* clear string to start */ 5334599Sbostic --mx; /* reserve room in string for nul terminator */ 5434599Sbostic 5534599Sbostic do 5634599Sbostic /* get characters and process */ 5734599Sbostic { 5834599Sbostic if (Echo) 5934599Sbostic mvaddstr(y, x, cp); /* print string on screen */ 6034599Sbostic clrtoeol(); /* clear any data after string */ 6134599Sbostic refresh(); /* update screen */ 6234599Sbostic 6334599Sbostic ch = getchar(); /* get character */ 6434599Sbostic 6534599Sbostic switch (ch) 6634599Sbostic { 6734599Sbostic case CH_ERASE: /* back up one character */ 6834599Sbostic if (inptr > cp) 6934599Sbostic --inptr; 7034599Sbostic break; 7134599Sbostic 7234599Sbostic case CH_KILL: /* back up to original location */ 7334599Sbostic inptr = cp; 7434599Sbostic break; 7534599Sbostic 7634599Sbostic case CH_NEWLINE: /* terminate string */ 7734599Sbostic break; 7834599Sbostic 7934599Sbostic case CH_REDRAW: /* redraw screen */ 8034599Sbostic clearok(stdscr, TRUE); 8134599Sbostic continue; 8234599Sbostic 8334599Sbostic default: /* put data in string */ 8434599Sbostic if (ch >= ' ' || Wizard) 8534599Sbostic /* printing char; put in string */ 8634599Sbostic *inptr++ = ch; 8734599Sbostic } 8834599Sbostic 8934599Sbostic *inptr = '\0'; /* terminate string */ 9034599Sbostic } 9134599Sbostic while (ch != CH_NEWLINE && inptr < cp + mx); 9234599Sbostic } 9334599Sbostic /**/ 9434599Sbostic /************************************************************************ 9534599Sbostic / 9634599Sbostic / FUNCTION NAME: more() 9734599Sbostic / 9834599Sbostic / FUNCTION: pause and prompt player 9934599Sbostic / 10034599Sbostic / AUTHOR: E. A. Estes, 12/4/85 10134599Sbostic / 10234599Sbostic / ARGUMENTS: 10334599Sbostic / int where - line on screen on which to pause 10434599Sbostic / 10534599Sbostic / RETURN VALUE: none 10634599Sbostic / 10734599Sbostic / MODULES CALLED: wmove(), waddstr(), getanswer() 10834599Sbostic / 10934599Sbostic / GLOBAL INPUTS: *stdscr 11034599Sbostic / 11134599Sbostic / GLOBAL OUTPUTS: none 11234599Sbostic / 11334599Sbostic / DESCRIPTION: 11434599Sbostic / Print a message, and wait for a space character. 11534599Sbostic / 11634599Sbostic /************************************************************************/ 11734599Sbostic 11834599Sbostic more(where) 11934599Sbostic int where; 12034599Sbostic { 12134599Sbostic mvaddstr(where, 0, "-- more --"); 12234599Sbostic getanswer(" ", FALSE); 12334599Sbostic } 12434599Sbostic /**/ 12534599Sbostic /************************************************************************ 12634599Sbostic / 12734599Sbostic / FUNCTION NAME: infloat() 12834599Sbostic / 12934599Sbostic / FUNCTION: input a floating point number from operator 13034599Sbostic / 13134599Sbostic / AUTHOR: E. A. Estes, 12/4/85 13234599Sbostic / 13334599Sbostic / ARGUMENTS: none 13434599Sbostic / 13534599Sbostic / RETURN VALUE: floating point number from operator 13634599Sbostic / 13734599Sbostic / MODULES CALLED: sscanf(), getstring() 13834599Sbostic / 13934599Sbostic / GLOBAL INPUTS: Databuf[] 14034599Sbostic / 14134599Sbostic / GLOBAL OUTPUTS: none 14234599Sbostic / 14334599Sbostic / DESCRIPTION: 14434599Sbostic / Read a string from player, and scan for a floating point 14534599Sbostic / number. 14634599Sbostic / If no valid number is found, return 0.0. 14734599Sbostic / 14834599Sbostic /************************************************************************/ 14934599Sbostic 15034599Sbostic double 15134599Sbostic infloat() 15234599Sbostic { 15334599Sbostic double result; /* return value */ 15434599Sbostic 15534599Sbostic getstring(Databuf, SZ_DATABUF); 156*34613Sbostic if (sscanf(Databuf, "%lf", &result) < 1) 15734599Sbostic /* no valid number entered */ 15834599Sbostic result = 0.0; 15934599Sbostic 16034599Sbostic return(result); 16134599Sbostic } 16234599Sbostic /**/ 16334599Sbostic /************************************************************************ 16434599Sbostic / 16534599Sbostic / FUNCTION NAME: inputoption() 16634599Sbostic / 16734599Sbostic / FUNCTION: input an option value from player 16834599Sbostic / 16934599Sbostic / AUTHOR: E. A. Estes, 12/4/85 17034599Sbostic / 17134599Sbostic / ARGUMENTS: none 17234599Sbostic / 17334599Sbostic / RETURN VALUE: none 17434599Sbostic / 17534599Sbostic / MODULES CALLED: floor(), drandom(), getanswer() 17634599Sbostic / 17734599Sbostic / GLOBAL INPUTS: Player 17834599Sbostic / 17934599Sbostic / GLOBAL OUTPUTS: Player 18034599Sbostic / 18134599Sbostic / DESCRIPTION: 18234599Sbostic / Age increases with every move. 18334599Sbostic / Refresh screen, and get a single character option from player. 18434599Sbostic / Return a random value if player's ring has gone bad. 18534599Sbostic / 18634599Sbostic /************************************************************************/ 18734599Sbostic 18834599Sbostic inputoption() 18934599Sbostic { 19034599Sbostic ++Player.p_age; /* increase age */ 19134599Sbostic 19234599Sbostic if (Player.p_ring.ring_type != R_SPOILED) 19334599Sbostic /* ring ok */ 19434599Sbostic return(getanswer("T ", TRUE)); 19534599Sbostic else 19634599Sbostic /* bad ring */ 19734599Sbostic { 19834599Sbostic getanswer(" ", TRUE); 19934599Sbostic return((int) ROLL(0.0, 5.0) + '0'); 20034599Sbostic } 20134599Sbostic } 20234599Sbostic /**/ 20334599Sbostic /************************************************************************ 20434599Sbostic / 20534599Sbostic / FUNCTION NAME: interrupt() 20634599Sbostic / 20734599Sbostic / FUNCTION: handle interrupt from operator 20834599Sbostic / 20934599Sbostic / AUTHOR: E. A. Estes, 12/4/85 21034599Sbostic / 21134599Sbostic / ARGUMENTS: none 21234599Sbostic / 21334599Sbostic / RETURN VALUE: none 21434599Sbostic / 21534599Sbostic / MODULES CALLED: fork(), exit(), wait(), death(), alarm(), execl(), wmove(), 21634599Sbostic / getgid(), signal(), getenv(), wclear(), setuid(), getuid(), setgid(), 21734599Sbostic / crmode(), clearok(), waddstr(), cleanup(), wrefresh(), leavegame(), 21834599Sbostic / getanswer() 21934599Sbostic / 22034599Sbostic / GLOBAL INPUTS: Player, *stdscr 22134599Sbostic / 22234599Sbostic / GLOBAL OUTPUTS: none 22334599Sbostic / 22434599Sbostic / DESCRIPTION: 22534599Sbostic / Allow player to quit upon hitting the interrupt key. 22634599Sbostic / If the player wants to quit while in battle, he/she automatically 22734599Sbostic / dies. 22834599Sbostic / If SHELL is defined, spawn a shell if the if the question is 22934599Sbostic / answered with a '!'. 23034599Sbostic / We are careful to save the state of the screen, and return it 23134599Sbostic / to its original condition. 23234599Sbostic / 23334599Sbostic /************************************************************************/ 23434599Sbostic 23534599Sbostic interrupt() 23634599Sbostic { 23734599Sbostic char line[81]; /* a place to store data already on screen */ 23834599Sbostic register int loop; /* counter */ 23934599Sbostic int x, y; /* coordinates on screen */ 24034599Sbostic int ch; /* input */ 24134599Sbostic unsigned savealarm; /* to save alarm value */ 24234599Sbostic #ifdef SHELL 24334599Sbostic register char *shell; /* pointer to shell to spawn */ 24434599Sbostic int childpid; /* pid of spawned process */ 24534599Sbostic #endif 24634599Sbostic 24734599Sbostic #ifdef SYS3 24834599Sbostic signal(SIGINT, SIG_IGN); 24934599Sbostic #endif 25034599Sbostic #ifdef SYS5 25134599Sbostic signal(SIGINT, SIG_IGN); 25234599Sbostic #endif 25334599Sbostic 25434599Sbostic savealarm = alarm(0); /* turn off any alarms */ 25534599Sbostic 25634599Sbostic getyx(stdscr, y, x); /* save cursor location */ 25734599Sbostic 25834599Sbostic for (loop = 0; loop < 80; ++loop) /* save line on screen */ 25934599Sbostic { 26034599Sbostic move(4, loop); 26134599Sbostic line[loop] = inch(); 26234599Sbostic } 26334599Sbostic line[80] = '\0'; /* nul terminate */ 26434599Sbostic 26534599Sbostic if (Player.p_status == S_INBATTLE || Player.p_status == S_MONSTER) 26634599Sbostic /* in midst of fighting */ 26734599Sbostic { 26834599Sbostic mvaddstr(4, 0, "Quitting now will automatically kill your character. Still want to ? "); 26934599Sbostic #ifdef SHELL 27034599Sbostic ch = getanswer("NY!", FALSE); 27134599Sbostic #else 27234599Sbostic ch = getanswer("NY", FALSE); 27334599Sbostic #endif 27434599Sbostic if (ch == 'Y') 27534599Sbostic death("Bailing out"); 27634599Sbostic /*NOTREACHED*/ 27734599Sbostic } 27834599Sbostic else 27934599Sbostic { 28034599Sbostic #ifdef SHELL 28134599Sbostic mvaddstr(4, 0, "Do you really want to quit [! = Shell] ? "); 28234599Sbostic ch = getanswer("NY!", FALSE); 28334599Sbostic #else 28434599Sbostic mvaddstr(4, 0, "Do you really want to quit ? "); 28534599Sbostic ch = getanswer("NY", FALSE); 28634599Sbostic #endif 28734599Sbostic if (ch == 'Y') 28834599Sbostic leavegame(); 28934599Sbostic /*NOTREACHED*/ 29034599Sbostic } 29134599Sbostic 29234599Sbostic #ifdef SHELL 29334599Sbostic if (ch == '!') 29434599Sbostic /* shell escape */ 29534599Sbostic { 29634599Sbostic if ((shell = getenv("SHELL")) == NULL) 29734599Sbostic /* use default */ 29834599Sbostic shell = SHELL; 29934599Sbostic 30034599Sbostic if ((childpid = fork()) == 0) 30134599Sbostic /* in child */ 30234599Sbostic { 30334599Sbostic clear(); 30434599Sbostic refresh(); 30534599Sbostic cleanup(FALSE); /* out of curses, close files */ 30634599Sbostic 30734599Sbostic setuid(getuid()); /* make sure we are running with real uid */ 30834599Sbostic setgid(getgid()); /* make sure we are running with real gid */ 30934599Sbostic execl(shell, shell, "-i", 0); 31034599Sbostic execl(SHELL, SHELL, "-i", 0); /* last resort */ 31134599Sbostic 31234599Sbostic exit(0); 31334599Sbostic /*NOTREACHED*/ 31434599Sbostic } 31534599Sbostic else 31634599Sbostic /* in parent */ 31734599Sbostic { 31834599Sbostic while (wait((int *) NULL) != childpid); /* wait until done */ 31934599Sbostic crmode(); /* restore keyboard */ 32034599Sbostic clearok(stdscr, TRUE); /* force redraw of screen */ 32134599Sbostic } 32234599Sbostic } 32334599Sbostic #endif 32434599Sbostic 32534599Sbostic mvaddstr(4, 0, line); /* restore data on screen */ 32634599Sbostic move(y, x); /* restore cursor */ 32734599Sbostic refresh(); 32834599Sbostic 32934599Sbostic #ifdef SYS3 33034599Sbostic signal(SIGINT, interrupt); 33134599Sbostic #endif 33234599Sbostic #ifdef SYS5 33334599Sbostic signal(SIGINT, interrupt); 33434599Sbostic #endif 33534599Sbostic 33634599Sbostic alarm(savealarm); /* restore alarm */ 33734599Sbostic } 33834599Sbostic /**/ 33934599Sbostic /************************************************************************ 34034599Sbostic / 34134599Sbostic / FUNCTION NAME: getanswer() 34234599Sbostic / 34334599Sbostic / FUNCTION: get an answer from operator 34434599Sbostic / 34534599Sbostic / AUTHOR: E. A. Estes, 12/4/85 34634599Sbostic / 34734599Sbostic / ARGUMENTS: 34834599Sbostic / char *choices - string of (upper case) valid choices 34934599Sbostic / bool def - set if default answer 35034599Sbostic / 35134599Sbostic / RETURN VALUE: none 35234599Sbostic / 35334599Sbostic / MODULES CALLED: alarm(), wmove(), waddch(), signal(), setjmp(), strchr(), 35434599Sbostic / _filbuf(), clearok(), toupper(), wrefresh(), mvprintw(), wclrtoeol() 35534599Sbostic / 35634599Sbostic / GLOBAL INPUTS: catchalarm(), Echo, _iob[], _ctype[], *stdscr, Timeout, 35734599Sbostic / Timeoenv[] 35834599Sbostic / 35934599Sbostic / GLOBAL OUTPUTS: _iob[] 36034599Sbostic / 36134599Sbostic / DESCRIPTION: 36234599Sbostic / Get a single character answer from operator. 36334599Sbostic / Timeout waiting for response. If we timeout, or the 36434599Sbostic / answer in not in the list of valid choices, print choices, 36534599Sbostic / and wait again, otherwise return the first character in ths 36634599Sbostic / list of choices. 36734599Sbostic / Give up after 3 tries. 36834599Sbostic / 36934599Sbostic /************************************************************************/ 37034599Sbostic 37134599Sbostic getanswer(choices, def) 37234599Sbostic char *choices; 37334599Sbostic bool def; 37434599Sbostic { 37534599Sbostic int ch; /* input */ 37634599Sbostic int loop; /* counter */ 37734599Sbostic int oldx, oldy; /* original coordinates on screen */ 37834599Sbostic 37934599Sbostic getyx(stdscr, oldy, oldx); 38034599Sbostic alarm(0); /* make sure alarm is off */ 38134599Sbostic 38234599Sbostic for (loop = 3; loop; --loop) 38334599Sbostic /* try for 3 times */ 38434599Sbostic { 38534599Sbostic if (setjmp(Timeoenv) != 0) 38634599Sbostic /* timed out waiting for response */ 38734599Sbostic { 38834599Sbostic if (def || loop <= 1) 38934599Sbostic /* return default answer */ 39034599Sbostic break; 39134599Sbostic else 39234599Sbostic /* prompt, and try again */ 39334599Sbostic goto YELL; 39434599Sbostic } 39534599Sbostic else 39634599Sbostic /* wait for response */ 39734599Sbostic { 39834599Sbostic clrtoeol(); 39934599Sbostic refresh(); 40034599Sbostic #ifdef BSD41 40134599Sbostic sigset(SIGALRM, catchalarm); 40234599Sbostic #else 40334599Sbostic signal(SIGALRM, catchalarm); 40434599Sbostic #endif 40534599Sbostic /* set timeout */ 40634599Sbostic if (Timeout) 40734599Sbostic alarm(7); /* short */ 40834599Sbostic else 40934599Sbostic alarm(600); /* long */ 41034599Sbostic 41134599Sbostic ch = getchar(); 41234599Sbostic 41334599Sbostic alarm(0); /* turn off timeout */ 41434599Sbostic 41534599Sbostic if (ch < 0) 41634599Sbostic /* caught some signal */ 41734599Sbostic { 41834599Sbostic ++loop; 41934599Sbostic continue; 42034599Sbostic } 42134599Sbostic else if (ch == CH_REDRAW) 42234599Sbostic /* redraw screen */ 42334599Sbostic { 42434599Sbostic clearok(stdscr, TRUE); /* force clear screen */ 42534599Sbostic ++loop; /* don't count this input */ 42634599Sbostic continue; 42734599Sbostic } 42834599Sbostic else if (Echo) 42934599Sbostic { 43034599Sbostic addch(ch); /* echo character */ 43134599Sbostic refresh(); 43234599Sbostic } 43334599Sbostic 43434599Sbostic if (islower(ch)) 43534599Sbostic /* convert to upper case */ 43634599Sbostic ch = toupper(ch); 43734599Sbostic 43834599Sbostic if (def || strchr(choices, ch) != NULL) 43934599Sbostic /* valid choice */ 44034599Sbostic return(ch); 44134599Sbostic else if (!def && loop > 1) 44234599Sbostic /* bad choice; prompt, and try again */ 44334599Sbostic { 44434599Sbostic YELL: mvprintw(oldy + 1, 0, "Please choose one of : [%s]\n", choices); 44534599Sbostic move(oldy, oldx); 44634599Sbostic clrtoeol(); 44734599Sbostic continue; 44834599Sbostic } 44934599Sbostic else 45034599Sbostic /* return default answer */ 45134599Sbostic break; 45234599Sbostic } 45334599Sbostic } 45434599Sbostic 45534599Sbostic return(*choices); 45634599Sbostic } 45734599Sbostic /**/ 45834599Sbostic /************************************************************************ 45934599Sbostic / 46034599Sbostic / FUNCTION NAME: catchalarm() 46134599Sbostic / 46234599Sbostic / FUNCTION: catch timer when waiting for input 46334599Sbostic / 46434599Sbostic / AUTHOR: E. A. Estes, 12/4/85 46534599Sbostic / 46634599Sbostic / ARGUMENTS: none 46734599Sbostic / 46834599Sbostic / RETURN VALUE: none 46934599Sbostic / 47034599Sbostic / MODULES CALLED: longjmp() 47134599Sbostic / 47234599Sbostic / GLOBAL INPUTS: Timeoenv[] 47334599Sbostic / 47434599Sbostic / GLOBAL OUTPUTS: none 47534599Sbostic / 47634599Sbostic / DESCRIPTION: 47734599Sbostic / Come here when the alarm expires while waiting for input. 47834599Sbostic / Simply longjmp() into getanswer(). 47934599Sbostic / 48034599Sbostic /************************************************************************/ 48134599Sbostic 48234599Sbostic catchalarm() 48334599Sbostic { 48434599Sbostic longjmp(Timeoenv, 1); 48534599Sbostic } 486