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