Annotation of early-roguelike/xrogue/io.c, Revision 1.1
1.1 ! rubenllo 1: /*
! 2: io.c - Various input/output functions
! 3:
! 4: XRogue: Expeditions into the Dungeons of Doom
! 5: Copyright (C) 1991 Robert Pietkivitch
! 6: All rights reserved.
! 7:
! 8: Based on "Advanced Rogue"
! 9: Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka and AT&T
! 10: All rights reserved.
! 11:
! 12: Based on "Rogue: Exploring the Dungeons of Doom"
! 13: Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
! 14: All rights reserved.
! 15:
! 16: See the file LICENSE.TXT for full copyright and licensing information.
! 17: */
! 18:
! 19: #include <curses.h>
! 20: #include <ctype.h>
! 21: #include <stdarg.h>
! 22: #include <string.h>
! 23: #include "rogue.h"
! 24:
! 25: void doadd(char *fmt, va_list ap);
! 26:
! 27: /*
! 28: * msg:
! 29: * Display a message at the top of the screen.
! 30: */
! 31:
! 32: static char msgbuf[BUFSIZ];
! 33: static int newpos = 0;
! 34:
! 35: /* VARARGS */
! 36: void
! 37: msg(char *fmt, ...)
! 38: {
! 39: va_list ap;
! 40: /*
! 41: * if the string is "", just clear the line
! 42: */
! 43: if (*fmt == '\0')
! 44: {
! 45: wclear(msgw);
! 46: overwrite(cw, msgw);
! 47: wmove(msgw, 0, 0);
! 48: clearok(msgw, FALSE);
! 49: draw(msgw);
! 50: mpos = 0;
! 51: return;
! 52: }
! 53: /*
! 54: * otherwise add to the message and flush it out
! 55: */
! 56: va_start(ap, fmt);
! 57: doadd(fmt, ap);
! 58: va_end(ap);
! 59: endmsg();
! 60: }
! 61:
! 62: /*
! 63: * add things to the current message
! 64: */
! 65:
! 66: /* VARARGS */
! 67: void
! 68: addmsg(char *fmt, ...)
! 69: {
! 70: va_list ap;
! 71:
! 72: va_start(ap, fmt);
! 73: doadd(fmt, ap);
! 74: va_end(ap);
! 75: }
! 76:
! 77: /*
! 78: * If there is no current message, do nothing. Otherwise, prompt the
! 79: * player with the --More-- string. Then erase the message.
! 80: */
! 81:
! 82: void
! 83: rmmsg(void)
! 84: {
! 85: if (mpos) {
! 86: wclear(msgw);
! 87: overwrite(cw, msgw);
! 88: mvwaddstr(msgw, 0, 0, huh);
! 89: waddstr(msgw, morestr);
! 90: clearok(msgw, FALSE);
! 91: draw(msgw);
! 92: wait_for(' ');
! 93: msg("");
! 94: }
! 95: }
! 96:
! 97: /*
! 98: * Display a new msg (giving him a chance to see the previous one if it
! 99: * is up there with the --More--)
! 100: */
! 101:
! 102: void
! 103: endmsg(void)
! 104: {
! 105: /* Needed to track where we are for 5.0 (PC) curses */
! 106: register int x, y;
! 107:
! 108: if (mpos) {
! 109: /*
! 110: * If this message will fit on the line (plus space for --More--)
! 111: * then just add it (only during combat).
! 112: */
! 113: if (player.t_quiet < 0 && mpos + newpos + strlen(morestr) + 5 < cols) {
! 114: wmove(msgw, 0, mpos + 5);
! 115: newpos += mpos + 5;
! 116: strcat(huh, " ");
! 117: }
! 118: else {
! 119: wclear(msgw);
! 120: overwrite(cw, msgw);
! 121: mvwaddstr(msgw, 0, 0, huh);
! 122: waddstr(msgw, morestr);
! 123: clearok(msgw, FALSE);
! 124: draw(msgw);
! 125: wait_for(' ');
! 126: wclear(msgw);
! 127: overwrite(cw, msgw);
! 128: wmove(msgw, 0, 0);
! 129: huh[0] = '\0';
! 130: }
! 131: }
! 132: else {
! 133: wclear(msgw);
! 134: overwrite(cw, msgw);
! 135: wmove(msgw, 0, 0);
! 136: huh[0] = '\0';
! 137: }
! 138: strcat(huh, msgbuf);
! 139: mvwaddstr(msgw, 0, 0, huh);
! 140: getyx(msgw, y, x);
! 141: mpos = newpos;
! 142: newpos = 0;
! 143: wmove(msgw, y, x);
! 144: clearok(msgw, FALSE);
! 145: draw(msgw);
! 146: }
! 147:
! 148: void
! 149: doadd(char *fmt, va_list ap)
! 150: {
! 151: vsprintf((char *) &msgbuf[newpos], fmt, ap);
! 152: newpos = strlen(msgbuf);
! 153: }
! 154:
! 155: /*
! 156: * step_ok:
! 157: * returns true if it is ok for type to step on ch
! 158: * flgptr will be NULL if we don't know what the monster is yet!
! 159: */
! 160:
! 161: bool
! 162: step_ok(int y, int x, int can_on_monst, struct thing *flgptr)
! 163: {
! 164: /* can_on_monst = MONSTOK if all we care about are physical obstacles */
! 165: register struct linked_list *item;
! 166: register struct thing *tp;
! 167: unsigned char ch;
! 168:
! 169: /* What is here? Don't check monster window if MONSTOK is set */
! 170: if (can_on_monst == MONSTOK) ch = mvinch(y, x);
! 171: else ch = winat(y, x);
! 172:
! 173: if (can_on_monst == FIGHTOK && isalpha(ch) &&
! 174: (item = find_mons(y, x)) != NULL) {
! 175: tp = THINGPTR(item); /* What monster is here? */
! 176:
! 177: /* We can hit it if we're after it */
! 178: if (flgptr->t_dest == &tp->t_pos) return TRUE;
! 179:
! 180: /*
! 181: * Otherwise, if we're friendly we'll hit it unless it is also
! 182: * friendly or is our race.
! 183: */
! 184: if (off(*flgptr, ISFRIENDLY) ||
! 185: on(*tp, ISFRIENDLY) ||
! 186: flgptr->t_index == tp->t_index) return FALSE;
! 187: else return TRUE;
! 188: }
! 189: else switch (ch)
! 190: {
! 191: case ' ':
! 192: case VERTWALL:
! 193: case HORZWALL:
! 194: case SECRETDOOR:
! 195: if (flgptr && on(*flgptr, CANINWALL)) return(TRUE);
! 196: return FALSE;
! 197: when SCROLL:
! 198: if (can_on_monst == MONSTOK) { /* Not a real obstacle */
! 199: move_free = 0; /* check free movement */
! 200: return(TRUE);
! 201: }
! 202: /*
! 203: * If it is a scroll, it might be a scare monster scroll
! 204: * so we need to look it up to see what type it is.
! 205: */
! 206: if (flgptr && flgptr->t_ctype == C_MONSTER) {
! 207: move_free = 1;
! 208: item = find_obj(y, x);
! 209: if (item != NULL &&
! 210: (OBJPTR(item))->o_which==S_SCARE &&
! 211: (flgptr == NULL || flgptr->t_stats.s_intel < 17)) {
! 212: move_free = 2;
! 213: return(FALSE); /* All but smart ones are scared */
! 214: }
! 215: }
! 216: return(TRUE);
! 217: otherwise:
! 218: return (!isalpha(ch));
! 219: }
! 220: /* return(FALSE); */
! 221: /*NOTREACHED*/
! 222: }
! 223:
! 224: /*
! 225: * shoot_ok:
! 226: * returns true if it is ok for type to shoot over ch
! 227: */
! 228:
! 229: bool
! 230: shoot_ok(int ch)
! 231: {
! 232: switch (ch)
! 233: {
! 234: case ' ':
! 235: case VERTWALL:
! 236: case HORZWALL:
! 237: case SECRETDOOR:
! 238: case FOREST:
! 239: return FALSE;
! 240: default:
! 241: return (!isalpha(ch));
! 242: }
! 243: }
! 244:
! 245: /*
! 246: * status:
! 247: * Display the important stats line. Keep the cursor where it was.
! 248: * display: is TRUE, display unconditionally
! 249: */
! 250:
! 251: void
! 252: status(bool display)
! 253: {
! 254: register struct stats *stat_ptr, *max_ptr;
! 255: register int oy = 0, ox = 0, temp;
! 256: register char *pb;
! 257: char buf[LINELEN];
! 258: static int hpwidth = 0, s_hungry = -1;
! 259: static int s_lvl = -1, s_hp = -1, s_str, maxs_str,
! 260: s_ac = 0;
! 261: static short s_intel, s_dext, s_wisdom, s_const, s_charisma;
! 262: static short maxs_intel, maxs_dext, maxs_wisdom, maxs_const, maxs_charisma;
! 263: static unsigned long s_exp = 0;
! 264: static int s_carry, s_pack;
! 265: bool first_line=FALSE;
! 266:
! 267: /* Go to English mode */
! 268: nofont(cw);
! 269:
! 270: stat_ptr = &pstats;
! 271: max_ptr = &max_stats;
! 272:
! 273: /*
! 274: * If nothing has changed in the first line, then skip it
! 275: */
! 276: if (!display &&
! 277: s_lvl == level &&
! 278: s_intel == stat_ptr->s_intel &&
! 279: s_wisdom == stat_ptr->s_wisdom &&
! 280: s_dext == dex_compute() &&
! 281: s_const == stat_ptr->s_const &&
! 282: s_charisma == stat_ptr->s_charisma &&
! 283: s_str == str_compute() &&
! 284: s_hungry == hungry_state &&
! 285: maxs_intel == max_ptr->s_intel &&
! 286: maxs_wisdom == max_ptr->s_wisdom &&
! 287: maxs_dext == max_ptr->s_dext &&
! 288: maxs_const == max_ptr->s_const &&
! 289: maxs_charisma == max_ptr->s_charisma &&
! 290: maxs_str == max_ptr->s_str ) goto line_two;
! 291:
! 292: /* Display the first line */
! 293: first_line = TRUE;
! 294: getyx(cw, oy, ox);
! 295: sprintf(buf, "Int:%d(%d) Str:%d", stat_ptr->s_intel,
! 296: max_ptr->s_intel, str_compute());
! 297:
! 298: /* Maximum strength */
! 299: pb = &buf[strlen(buf)];
! 300: sprintf(pb, "(%d)", max_ptr->s_str);
! 301:
! 302: pb = &buf[strlen(buf)];
! 303: sprintf(pb, " Wis:%d(%d) Dxt:%d(%d) Con:%d(%d) Cha:%d(%d)",
! 304: stat_ptr->s_wisdom,max_ptr->s_wisdom,dex_compute(),max_ptr->s_dext,
! 305: stat_ptr->s_const,max_ptr->s_const,stat_ptr->s_charisma,
! 306: max_ptr->s_charisma);
! 307:
! 308: /* Update first line status */
! 309: s_intel = stat_ptr->s_intel;
! 310: s_wisdom = stat_ptr->s_wisdom;
! 311: s_dext = dex_compute();
! 312: s_const = stat_ptr->s_const;
! 313: s_charisma = stat_ptr->s_charisma;
! 314: s_str = str_compute();
! 315: maxs_intel = max_ptr->s_intel;
! 316: maxs_wisdom = max_ptr->s_wisdom;
! 317: maxs_dext = max_ptr->s_dext;
! 318: maxs_const = max_ptr->s_const;
! 319: maxs_charisma = max_ptr->s_charisma;
! 320: maxs_str = max_ptr->s_str;
! 321:
! 322: /* Print the line */
! 323: mvwaddstr(cw, lines-2, 0, buf);
! 324: switch (hungry_state) {
! 325: case F_SATIATED:
! 326: waddstr(cw, " Satiated");
! 327: when F_OKAY: ;
! 328: when F_HUNGRY:
! 329: waddstr(cw, " Hungry");
! 330: when F_WEAK:
! 331: waddstr(cw, " Weak");
! 332: when F_FAINT:
! 333: waddstr(cw, " Fainting");
! 334: }
! 335: wclrtoeol(cw);
! 336: s_hungry = hungry_state;
! 337:
! 338: /*
! 339: * If nothing has changed since the last status, don't
! 340: * bother.
! 341: */
! 342: line_two:
! 343: if (!display &&
! 344: s_lvl == level &&
! 345: s_hp == stat_ptr->s_hpt &&
! 346: s_ac == ac_compute(FALSE) - dext_prot(s_dext) &&
! 347: s_pack == stat_ptr->s_pack &&
! 348: s_carry == stat_ptr->s_carry &&
! 349: s_exp == stat_ptr->s_exp ) {
! 350: newfont(cw);
! 351: return;
! 352: }
! 353:
! 354: if (!first_line) getyx(cw, oy, ox);
! 355: if (s_hp != max_ptr->s_hpt) {
! 356: temp = s_hp = max_ptr->s_hpt;
! 357: for (hpwidth = 0; temp; hpwidth++)
! 358: temp /= 10;
! 359: }
! 360: sprintf(buf, "Lvl:%d Hp:%*d(%*d) Ac:%d Carry:%d(%d) Exp:%d/%lu %s",
! 361: level, hpwidth, stat_ptr->s_hpt, hpwidth, max_ptr->s_hpt,
! 362: ac_compute(FALSE) - dext_prot(s_dext),stat_ptr->s_pack/10,
! 363: stat_ptr->s_carry/10, stat_ptr->s_lvl, stat_ptr->s_exp,
! 364: cnames[player.t_ctype][min(stat_ptr->s_lvl-1, NUM_CNAMES-1)]);
! 365:
! 366: /*
! 367: * Save old status
! 368: */
! 369: s_lvl = level;
! 370: s_hp = stat_ptr->s_hpt;
! 371: s_ac = ac_compute(FALSE) - dext_prot(s_dext);
! 372: s_pack = stat_ptr->s_pack;
! 373: s_carry = stat_ptr->s_carry;
! 374: s_exp = stat_ptr->s_exp;
! 375: mvwaddstr(cw, lines-1, 0, buf);
! 376: wclrtoeol(cw);
! 377: newfont(cw);
! 378: wmove(cw, oy, ox);
! 379: }
! 380:
! 381: /*
! 382: * wait_for
! 383: * Sit around until the guy types the right key
! 384: */
! 385:
! 386: void
! 387: wait_for(char ch)
! 388: {
! 389: register char c;
! 390:
! 391: clearok(msgw, FALSE);
! 392: if (ch == '\n') {
! 393: while ((c = wgetch(msgw)) != '\n' && c != '\r') {
! 394: continue;
! 395: }
! 396: }
! 397: else {
! 398: while (wgetch(msgw) != ch) {
! 399: continue;
! 400: }
! 401: }
! 402: }
! 403:
! 404:
! 405: /*
! 406: * over_win:
! 407: * Given a current window, a new window, and the max y and x of the
! 408: * new window, paint the new window on top of the old window without
! 409: * destroying any of the old window. Current window and new window
! 410: * are assumed to have lines lines and cols columns (max y and max x
! 411: * pertain only the the useful information to be displayed.
! 412: * If redraw is non-zero, we wait for the character "redraw" to be
! 413: * typed and then redraw the starting screen.
! 414: */
! 415:
! 416: void
! 417: over_win(WINDOW *oldwin, WINDOW *newin, int maxy, int maxx, int cursory,
! 418: int cursorx, char redraw)
! 419: {
! 420: char blanks[LINELEN+1];
! 421: register int line, i;
! 422: WINDOW *ow; /* Overlay window */
! 423:
! 424: /* Create a blanking line */
! 425: for (i=0; i<maxx && i<cols && i<LINELEN; i++) blanks[i] = ' ';
! 426: blanks[i] = '\0';
! 427:
! 428: /* Create the window we will display */
! 429: ow = newwin(lines, cols, 0, 0);
! 430:
! 431: /* Blank out the area we want to use */
! 432: if (oldwin == cw) {
! 433: msg("");
! 434: line = 1;
! 435: }
! 436: else line = 0;
! 437:
! 438: overwrite(oldwin, ow); /* Get a copy of the old window */
! 439:
! 440: /* Do the remaining blanking */
! 441: for (; line < maxy; line++) mvwaddstr(ow, line, 0, blanks);
! 442:
! 443: overlay(newin, ow); /* Overlay our new window */
! 444:
! 445: /* Move the cursor to the specified location */
! 446: wmove(ow, cursory, cursorx);
! 447:
! 448: clearok(ow, FALSE); /* Draw inventory without clearing */
! 449: draw(ow);
! 450:
! 451: if (redraw) {
! 452: wait_for(redraw);
! 453:
! 454: clearok(oldwin, FALSE); /* Setup to redraw current screen */
! 455: touchwin(oldwin); /* clearing first */
! 456: draw(oldwin);
! 457: }
! 458:
! 459: delwin(ow);
! 460: }
! 461:
! 462:
! 463: /*
! 464: * show_win:
! 465: * function used to display a window and wait before returning
! 466: */
! 467:
! 468: void
! 469: show_win(WINDOW *scr, char *message)
! 470: {
! 471: mvwaddstr(scr, 0, 0, message);
! 472: touchwin(scr);
! 473: wmove(scr, hero.y, hero.x);
! 474: draw(scr);
! 475: wait_for(' ');
! 476: restscr(cw);
! 477: }
! 478:
! 479: /*
! 480: * dbotline:
! 481: * Displays message on bottom line and waits for a space to return
! 482: */
! 483:
! 484: void
! 485: dbotline(WINDOW *scr, char *message)
! 486: {
! 487: mvwaddstr(scr,lines-1,0,message);
! 488: draw(scr);
! 489: wait_for(' ');
! 490: }
! 491:
! 492: /*
! 493: * restscr:
! 494: * Restores the screen to the terminal
! 495: */
! 496:
! 497: void
! 498: restscr(WINDOW *scr)
! 499: {
! 500: clearok(scr,TRUE);
! 501: touchwin(scr);
! 502: draw(scr);
! 503: }
! 504:
! 505: /*
! 506: * netread:
! 507: * Read a byte, short, or long machine independently
! 508: * Always returns the value as an unsigned long.
! 509: */
! 510:
! 511: unsigned long
! 512: netread(int *error, int size, FILE *stream)
! 513: {
! 514: unsigned long result = 0L, /* What we read in */
! 515: partial; /* Partial value */
! 516: int nextc, /* The next byte */
! 517: i; /* To index through the result a byte at a time */
! 518:
! 519: /* Be sure we have a right sized chunk */
! 520: if (size < 1 || size > 4) {
! 521: *error = 1;
! 522: return(0L);
! 523: }
! 524:
! 525: for (i=0; i<size; i++) {
! 526: nextc = getc(stream);
! 527: if (nextc == EOF) {
! 528: *error = 1;
! 529: return(0L);
! 530: }
! 531: else {
! 532: partial = (unsigned long) (nextc & 0xff);
! 533: partial <<= 8*i;
! 534: result |= partial;
! 535: }
! 536: }
! 537:
! 538: *error = 0;
! 539: return(result);
! 540: }
! 541:
! 542: /*
! 543: * netwrite:
! 544: * Write out a byte, short, or long machine independently.
! 545: * value: What to write
! 546: * size: How much to write out
! 547: * stream: Where to write it
! 548: */
! 549:
! 550: int
! 551: netwrite(unsigned long value, int size, FILE *stream)
! 552: {
! 553: int i; /* Goes through value one byte at a time */
! 554: char outc; /* The next character to be written */
! 555:
! 556: /* Be sure we have a right sized chunk */
! 557: if (size < 1 || size > 4) return(0);
! 558:
! 559: for (i=0; i<size; i++) {
! 560: outc = (char) ((value >> (8 * i)) & 0xff);
! 561: putc(outc, stream);
! 562: }
! 563: return(size);
! 564: }
! 565:
CVSweb