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 */ 6 7 #include <string.h> 8 #include "include.h" 9 10 /* functions which we need to know about */ 11 /* misc.c */ 12 extern void death(const char *); 13 extern void leavegame(void); 14 /* phantglobs.c */ 15 extern double drandom(void); 16 17 void catchalarm(int); 18 int getanswer(const char *, bool); 19 void getstring(char *, int); 20 double infloat(void); 21 int inputoption(void); 22 void interrupt(void); 23 void more(int); 24 25 /* 26 * FUNCTION: read a string from operator 27 * 28 * ARGUMENTS: 29 * char *cp - pointer to buffer area to fill 30 * int mx - maximum number of characters to put in buffer 31 * 32 * GLOBAL INPUTS: Echo, _iob[], Wizard, *stdscr 33 * 34 * GLOBAL OUTPUTS: _iob[] 35 * 36 * DESCRIPTION: 37 * Read a string from the keyboard. 38 * This routine is specially designed to: 39 * 40 * - strip non-printing characters (unless Wizard) 41 * - echo, if desired 42 * - redraw the screen if CH_REDRAW is entered 43 * - read in only 'mx - 1' characters or less characters 44 * - nul-terminate string, and throw away newline 45 * 46 * 'mx' is assumed to be at least 2. 47 */ 48 49 void 50 getstring(char *cp, int mx) 51 { 52 char *inptr; /* pointer into string for next string */ 53 int x, y; /* original x, y coordinates on screen */ 54 int ch; /* input */ 55 56 getyx(stdscr, y, x); /* get coordinates on screen */ 57 inptr = cp; 58 *inptr = '\0'; /* clear string to start */ 59 --mx; /* reserve room in string for nul terminator */ 60 61 do { 62 /* get characters and process */ 63 if (Echo) 64 mvaddstr(y, x, cp); /* print string on screen */ 65 clrtoeol(); /* clear any data after string */ 66 refresh(); /* update screen */ 67 68 ch = getchar(); /* get character */ 69 70 switch (ch) { 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 } while (ch != CH_NEWLINE && inptr < cp + mx); 95 } 96 97 /* 98 * FUNCTION: pause and prompt player 99 * 100 * ARGUMENTS: 101 * int where - line on screen on which to pause 102 * 103 * GLOBAL INPUTS: *stdscr 104 * 105 * DESCRIPTION: 106 * Print a message, and wait for a space character. 107 */ 108 109 void 110 more(int where) 111 { 112 mvaddstr(where, 0, "-- more --"); 113 getanswer(" ", FALSE); 114 } 115 116 /* 117 * FUNCTION: input a floating point number from operator 118 * 119 * RETURN VALUE: floating point number from operator 120 * 121 * GLOBAL INPUTS: Databuf[] 122 * 123 * DESCRIPTION: 124 * Read a string from player, and scan for a floating point 125 * number. 126 * If no valid number is found, return 0.0. 127 */ 128 129 double 130 infloat(void) 131 { 132 double result; /* return value */ 133 134 getstring(Databuf, SZ_DATABUF); 135 if (sscanf(Databuf, "%lf", &result) < 1) 136 /* no valid number entered */ 137 result = 0.0; 138 139 return (result); 140 } 141 142 /* 143 * FUNCTION: input an option value from player 144 * 145 * GLOBAL INPUTS: Player 146 * 147 * GLOBAL OUTPUTS: Player 148 * 149 * DESCRIPTION: 150 * Age increases with every move. 151 * Refresh screen, and get a single character option from player. 152 * Return a random value if player's ring has gone bad. 153 */ 154 155 int 156 inputoption(void) 157 { 158 ++Player.p_age; /* increase age */ 159 160 if (Player.p_ring.ring_type != R_SPOILED) 161 /* ring ok */ 162 return (getanswer("T ", TRUE)); 163 else { 164 /* bad ring */ 165 getanswer(" ", TRUE); 166 return ((int)ROLL(0.0, 5.0) + '0'); 167 } 168 } 169 170 /* 171 * FUNCTION: handle interrupt from operator 172 * 173 * GLOBAL INPUTS: Player, *stdscr 174 * 175 * DESCRIPTION: 176 * Allow player to quit upon hitting the interrupt key. 177 * If the player wants to quit while in battle, he/she automatically 178 * dies. 179 */ 180 181 void 182 interrupt(void) 183 { 184 char line[81]; /* a place to store data already on screen */ 185 int loop; /* counter */ 186 int x, y; /* coordinates on screen */ 187 int ch; /* input */ 188 unsigned savealarm; /* to save alarm value */ 189 190 #ifdef SYS3 191 signal(SIGINT, SIG_IGN); 192 #endif 193 #ifdef SYS5 194 signal(SIGINT, SIG_IGN); 195 #endif 196 197 savealarm = alarm(0); /* turn off any alarms */ 198 199 getyx(stdscr, y, x); /* save cursor location */ 200 201 for (loop = 0; loop < 80; ++loop) { /* save line on screen */ 202 move(4, loop); 203 line[loop] = inch(); 204 } 205 line[80] = '\0'; /* nul terminate */ 206 207 if (Player.p_status == S_INBATTLE || Player.p_status == S_MONSTER) { 208 /* in midst of fighting */ 209 mvaddstr(4, 0, "Quitting now will automatically kill your character. Still want to ? "); 210 ch = getanswer("NY", FALSE); 211 if (ch == 'Y') 212 death("Bailing out"); 213 /* NOTREACHED */ 214 } else { 215 mvaddstr(4, 0, "Do you really want to quit ? "); 216 ch = getanswer("NY", FALSE); 217 if (ch == 'Y') 218 leavegame(); 219 /* NOTREACHED */ 220 } 221 222 mvaddstr(4, 0, line); /* restore data on screen */ 223 move(y, x); /* restore cursor */ 224 refresh(); 225 226 #ifdef SYS3 227 signal(SIGINT, interrupt); 228 #endif 229 #ifdef SYS5 230 signal(SIGINT, interrupt); 231 #endif 232 233 alarm(savealarm); /* restore alarm */ 234 } 235 236 /* 237 * FUNCTION: get an answer from operator 238 * 239 * ARGUMENTS: 240 * char *choices - string of (upper case) valid choices 241 * bool def - set if default answer 242 * 243 * GLOBAL INPUTS: catchalarm(), Echo, _iob[], _ctype[], *stdscr, Timeout, 244 * Timeoenv[] 245 * 246 * GLOBAL OUTPUTS: _iob[] 247 * 248 * DESCRIPTION: 249 * Get a single character answer from operator. 250 * Timeout waiting for response. If we timeout, or the 251 * answer in not in the list of valid choices, print choices, 252 * and wait again, otherwise return the first character in ths 253 * list of choices. 254 * Give up after 3 tries. 255 */ 256 257 int 258 getanswer(const char *choices, bool def) 259 { 260 int ch; /* input */ 261 volatile int loop; /* counter */ 262 volatile int oldx, oldy; /* original coordinates on screen */ 263 264 getyx(stdscr, oldy, oldx); 265 alarm(0); /* make sure alarm is off */ 266 267 for (loop = 3; loop; --loop) { 268 /* try for 3 times */ 269 if (setjmp(Timeoenv) != 0) { 270 /* timed out waiting for response */ 271 if (def || loop <= 1) 272 /* return default answer */ 273 break; 274 else 275 /* prompt, and try again */ 276 goto YELL; 277 } else { 278 /* wait for response */ 279 clrtoeol(); 280 refresh(); 281 #ifdef BSD41 282 sigset(SIGALRM, catchalarm); 283 #else 284 signal(SIGALRM, catchalarm); 285 #endif 286 /* set timeout */ 287 if (Timeout) 288 alarm(7); /* short */ 289 else 290 alarm(600); /* long */ 291 292 ch = getchar(); 293 294 alarm(0); /* turn off timeout */ 295 296 if (ch < 0) { 297 /* caught some signal */ 298 ++loop; 299 continue; 300 } else if (ch == CH_REDRAW) { 301 /* redraw screen */ 302 clearok(stdscr, TRUE); /* force clear screen */ 303 ++loop; /* don't count this input */ 304 continue; 305 } else if (Echo) { 306 addch(ch); /* echo character */ 307 refresh(); 308 } 309 310 if (islower(ch)) 311 /* convert to upper case */ 312 ch = toupper(ch); 313 314 if (def || strchr(choices, ch) != NULL) 315 /* valid choice */ 316 return (ch); 317 else if (!def && loop > 1) { 318 /* bad choice; prompt, and try again */ 319 YELL: mvprintw(oldy + 1, 0, 320 "Please choose one of : [%s]\n", choices); 321 move(oldy, oldx); 322 clrtoeol(); 323 continue; 324 } else 325 /* return default answer */ 326 break; 327 } 328 } 329 330 return (*choices); 331 } 332 333 /* 334 * FUNCTION: catch timer when waiting for input 335 * 336 * GLOBAL INPUTS: Timeoenv[] 337 * 338 * DESCRIPTION: 339 * Come here when the alarm expires while waiting for input. 340 * Simply longjmp() into getanswer(). 341 */ 342 343 void 344 catchalarm(__unused int sig) 345 { 346 longjmp(Timeoenv, 1); 347 } 348