Annotation of early-roguelike/xrogue/io.c, Revision 1.1.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