xref: /dragonfly/games/hack/hack.pri.c (revision 36a3d1d6)
1 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
2 /* hack.pri.c - version 1.0.3 */
3 /* $FreeBSD: src/games/hack/hack.pri.c,v 1.5 1999/11/16 10:26:37 marcel Exp $ */
4 /* $DragonFly: src/games/hack/hack.pri.c,v 1.5 2006/08/21 19:45:32 pavalos Exp $ */
5 
6 #include "hack.h"
7 #include <curses.h>
8 xchar scrlx, scrhx, scrly, scrhy;	/* corners of new area on screen */
9 
10 extern char *CD;
11 
12 #ifdef NEWSCR
13 static void	pobj(struct obj *);
14 #endif
15 static void	cornbot(int);
16 
17 void
18 swallowed(void)
19 {
20 	char ulook[] = { "|@|" };
21 
22 	ulook[1] = u.usym;
23 
24 	cls();
25 	curs(u.ux - 1, u.uy + 1);
26 	fputs("/-\\", stdout);
27 	curx = u.ux + 2;
28 	curs(u.ux - 1, u.uy + 2);
29 	fputs(ulook, stdout);
30 	curx = u.ux + 2;
31 	curs(u.ux - 1, u.uy + 3);
32 	fputs("\\-/", stdout);
33 	curx = u.ux + 2;
34 	u.udispl = 1;
35 	u.udisx = u.ux;
36 	u.udisy = u.uy;
37 }
38 
39 /* VARARGS1 */
40 boolean panicking;
41 
42 void
43 panic(const char *str, ...)
44 {
45 	va_list ap;
46 
47 	if (panicking++)	/* avoid loops - this should never happen*/
48 		exit(1);
49 	home();
50 	puts(" Suddenly, the dungeon collapses.");
51 	fputs(" ERROR:  ", stdout);
52 	va_start(ap, str);
53 	vprintf(str, ap);
54 	va_end(ap);
55 #ifdef DEBUG
56 #ifdef UNIX
57 	if (!fork())
58 		abort();	/* generate core dump */
59 #endif /* UNIX */
60 #endif /* DEBUG */
61 	more();			/* contains a fflush() */
62 	done("panicked");
63 }
64 
65 void
66 atl(int x, int y, char ch)
67 {
68 	struct rm *crm = &levl[x][y];
69 
70 	if (x < 0 || x > COLNO - 1 || y < 0 || y > ROWNO - 1) {
71 		impossible("atl(%d,%d,%c)", x, y, ch);
72 		return;
73 	}
74 	if (crm->seen && crm->scrsym == ch)
75 		return;
76 	crm->scrsym = ch;
77 	crm->new = 1;
78 	on_scr(x, y);
79 }
80 
81 void
82 on_scr(int x, int y)
83 {
84 	if (x < scrlx)
85 		scrlx = x;
86 	if (x > scrhx)
87 		scrhx = x;
88 	if (y < scrly)
89 		scrly = y;
90 	if (y > scrhy)
91 		scrhy = y;
92 }
93 
94 /* call: (x,y) - display
95  *      (-1,0) - close (leave last symbol)
96  *      (-1,-1)- close (undo last symbol)
97  *      (-1,let)-open: initialize symbol
98  *      (-2,let)-change let
99  */
100 
101 void
102 tmp_at(schar x, schar y)
103 {
104 	static schar prevx, prevy;
105 	static char let;
106 
107 	if ((int)x == -2) {		/* change let call */
108 		let = y;
109 		return;
110 	}
111 	if ((int)x == -1 && (int)y >= 0) {	/* open or close call */
112 		let = y;
113 		prevx = -1;
114 		return;
115 	}
116 	if (prevx >= 0 && cansee(prevx, prevy)) {
117 		delay_output(50);
118 		prl(prevx, prevy);	/* in case there was a monster */
119 		at(prevx, prevy, levl[prevx][prevy].scrsym);
120 	}
121 	if (x >= 0) {			/* normal call */
122 		if (cansee(x, y))
123 			at(x, y, let);
124 		prevx = x;
125 		prevy = y;
126 	} else {			/* close call */
127 		let = 0;
128 		prevx = -1;
129 	}
130 }
131 
132 /* like the previous, but the symbols are first erased on completion */
133 void
134 Tmp_at(schar x, schar y)
135 {
136 	static char let;
137 	static xchar cnt;
138 	static coord tc[COLNO];	/* but watch reflecting beams! */
139 	int xx, yy;
140 
141 	if ((int)x == -1) {
142 		if (y > 0) {	/* open call */
143 			let = y;
144 			cnt = 0;
145 			return;
146 		}
147 		/* close call (do not distinguish y==0 and y==-1) */
148 		while (cnt--) {
149 			xx = tc[cnt].x;
150 			yy = tc[cnt].y;
151 			prl(xx, yy);
152 			at(xx, yy, levl[xx][yy].scrsym);
153 		}
154 		cnt = let = 0;	/* superfluous */
155 		return;
156 	}
157 	if ((int)x == -2) {	/* change let call */
158 		let = y;
159 		return;
160 	}
161 	/* normal call */
162 	if (cansee(x, y)) {
163 		if (cnt)
164 			delay_output(50);
165 		at(x, y, let);
166 		tc[cnt].x = x;
167 		tc[cnt].y = y;
168 		if (++cnt >= COLNO)
169 			panic("Tmp_at overflow?");
170 		levl[x][y].new = 0;	/* prevent pline-nscr erasing --- */
171 	}
172 }
173 
174 void
175 setclipped(void)
176 {
177 	error("Hack needs a screen of size at least %d by %d.\n",
178 	      ROWNO + 2, COLNO);
179 }
180 
181 void
182 at(xchar x, xchar y, char ch)
183 {
184 #ifndef lint
185 	/* if xchar is unsigned, lint will complain about if (x < 0)  */
186 	if (x < 0 || x > COLNO - 1 || y < 0 || y > ROWNO - 1) {
187 		impossible("At gets 0%o at %d %d.", ch, x, y);
188 		return;
189 	}
190 #endif /* lint */
191 	if (!ch) {
192 		impossible("At gets null at %d %d.", x, y);
193 		return;
194 	}
195 	y += 2;
196 	curs(x, y);
197 	putchar(ch);
198 	curx++;
199 }
200 
201 void
202 prme(void)
203 {
204 	if (!Invisible)
205 		at(u.ux, u.uy, u.usym);
206 }
207 
208 int
209 doredraw(void)
210 {
211 	docrt();
212 	return (0);
213 }
214 
215 void
216 docrt(void)
217 {
218 	int x, y;
219 	struct rm *room;
220 	struct monst *mtmp;
221 
222 	if (u.uswallow) {
223 		swallowed();
224 		return;
225 	}
226 	cls();
227 
228 /* Some ridiculous code to get display of @ and monsters (almost) right */
229 	if (!Invisible) {
230 		levl[(u.udisx = u.ux)][(u.udisy = u.uy)].scrsym = u.usym;
231 		levl[u.udisx][u.udisy].seen = 1;
232 		u.udispl = 1;
233 	} else
234 		u.udispl = 0;
235 
236 	seemons();		/* reset old positions */
237 	for (mtmp = fmon; mtmp; mtmp = mtmp->nmon)
238 		mtmp->mdispl = 0;
239 	seemons();		/* force new positions to be shown */
240 /* This nonsense should disappear soon --------------------------------- */
241 
242 	for (y = 0; y < ROWNO; y++)
243 		for (x = 0; x < COLNO; x++)
244 			if ((room = &levl[x][y])->new) {
245 				room->new = 0;
246 				at(x, y, room->scrsym);
247 			} else if (room->seen)
248 				at(x, y, room->scrsym);
249 	scrlx = COLNO;
250 	scrly = ROWNO;
251 	scrhx = scrhy = 0;
252 	flags.botlx = 1;
253 	bot();
254 }
255 
256 void
257 docorner(int xmin, int ymax)
258 {
259 	int x, y;
260 	struct rm *room;
261 	struct monst *mtmp;
262 
263 	if (u.uswallow) {	/* Can be done more efficiently */
264 		swallowed();
265 		return;
266 	}
267 	seemons();		/* reset old positions */
268 	for (mtmp = fmon; mtmp; mtmp = mtmp->nmon)
269 		if (mtmp->mx >= xmin && mtmp->my < ymax)
270 			mtmp->mdispl = 0;
271 	seemons();		/* force new positions to be shown */
272 
273 	for (y = 0; y < ymax; y++) {
274 		if (y > ROWNO && CD)
275 			break;
276 		curs(xmin, y + 2);
277 		cl_end();
278 		if (y < ROWNO) {
279 			for (x = xmin; x < COLNO; x++) {
280 				if ((room = &levl[x][y])->new) {
281 					room->new = 0;
282 					at(x, y, room->scrsym);
283 				} else if (room->seen)
284 					at(x, y, room->scrsym);
285 			}
286 		}
287 	}
288 	if (ymax > ROWNO) {
289 		cornbot(xmin - 1);
290 		if (ymax > ROWNO + 1 && CD) {
291 			curs(1, ROWNO + 3);
292 			cl_eos();
293 		}
294 	}
295 }
296 
297 void
298 curs_on_u(void)
299 {
300 	curs(u.ux, u.uy + 2);
301 }
302 
303 void
304 pru(void)
305 {
306 	if (u.udispl && (Invisible || u.udisx != u.ux || u.udisy != u.uy))
307 		if (!vism_at(u.udisx, u.udisy))
308 			newsym(u.udisx, u.udisy);
309 	if (Invisible) {
310 		u.udispl = 0;
311 		prl(u.ux, u.uy);
312 	} else if (!u.udispl || u.udisx != u.ux || u.udisy != u.uy) {
313 		atl(u.ux, u.uy, u.usym);
314 		u.udispl = 1;
315 		u.udisx = u.ux;
316 		u.udisy = u.uy;
317 	}
318 	levl[u.ux][u.uy].seen = 1;
319 }
320 
321 #ifndef NOWORM
322 extern struct wseg *m_atseg;
323 #endif /* NOWORM */
324 
325 /* print a position that is visible for @ */
326 void
327 prl(int x, int y)
328 {
329 	struct rm *room;
330 	struct monst *mtmp;
331 	struct obj *otmp;
332 
333 	if (x == u.ux && y == u.uy && (!Invisible)) {
334 		pru();
335 		return;
336 	}
337 	if (!isok(x, y))
338 		return;
339 	room = &levl[x][y];
340 	if ((!room->typ) ||
341 	    (IS_ROCK(room->typ) && levl[u.ux][u.uy].typ == CORR))
342 		return;
343 	if ((mtmp = m_at(x, y)) && !mtmp->mhide &&
344 	    (!mtmp->minvis || See_invisible)) {
345 #ifndef NOWORM
346 		if (m_atseg)
347 			pwseg(m_atseg);
348 		else
349 #endif /* NOWORM */
350 			pmon(mtmp);
351 	} else if ((otmp = o_at(x, y)) && room->typ != POOL)
352 		atl(x, y, otmp->olet);
353 	else if (mtmp && (!mtmp->minvis || See_invisible)) {
354 		/* must be a hiding monster, but not hiding right now */
355 		/* assume for the moment that long worms do not hide */
356 		pmon(mtmp);
357 	} else if (g_at(x, y) && room->typ != POOL)
358 		atl(x, y, '$');
359 	else if (!room->seen || room->scrsym == ' ') {
360 		room->new = room->seen = 1;
361 		newsym(x, y);
362 		on_scr(x, y);
363 	}
364 	room->seen = 1;
365 }
366 
367 char
368 news0(xchar x, xchar y)
369 {
370 	struct obj *otmp;
371 	struct trap *ttmp;
372 	struct rm *room;
373 	char tmp;
374 
375 	room = &levl[x][y];
376 	if (!room->seen)
377 		tmp = ' ';
378 	else if (room->typ == POOL)
379 		tmp = POOL_SYM;
380 	else if (!Blind && (otmp = o_at(x, y)))
381 		tmp = otmp->olet;
382 	else if (!Blind && g_at(x, y))
383 		tmp = '$';
384 	else if (x == xupstair && y == yupstair)
385 		tmp = '<';
386 	else if (x == xdnstair && y == ydnstair)
387 		tmp = '>';
388 	else if ((ttmp = t_at(x, y)) && ttmp->tseen)
389 		tmp = '^';
390 	else
391 		switch (room->typ) {
392 		case SCORR:
393 		case SDOOR:
394 			tmp = room->scrsym;	/* %% wrong after killing mimic ! */
395 			break;
396 		case HWALL:
397 			tmp = '-';
398 			break;
399 		case VWALL:
400 			tmp = '|';
401 			break;
402 		case LDOOR:
403 		case DOOR:
404 			tmp = '+';
405 			break;
406 		case CORR:
407 			tmp = CORR_SYM;
408 			break;
409 		case ROOM:
410 			if (room->lit || cansee(x, y) || Blind)
411 				tmp = '.';
412 			else
413 				tmp = ' ';
414 			break;
415 		default:
416 			tmp = ERRCHAR;
417 		}
418 	return (tmp);
419 }
420 
421 void
422 newsym(int x, int y)
423 {
424 	atl(x, y, news0(x, y));
425 }
426 
427 /* used with wand of digging (or pick-axe): fill scrsym and force display */
428 /* also when a POOL evaporates */
429 void
430 mnewsym(int x, int y)
431 {
432 	struct rm *room;
433 	char newscrsym;
434 
435 	if (!vism_at(x, y)) {
436 		room = &levl[x][y];
437 		newscrsym = news0(x, y);
438 		if (room->scrsym != newscrsym) {
439 			room->scrsym = newscrsym;
440 			room->seen = 0;
441 		}
442 	}
443 }
444 
445 void
446 nosee(int x, int y)
447 {
448 	struct rm *room;
449 
450 	if (!isok(x, y))
451 		return;
452 	room = &levl[x][y];
453 	if (room->scrsym == '.' && !room->lit && !Blind) {
454 		room->scrsym = ' ';
455 		room->new = 1;
456 		on_scr(x, y);
457 	}
458 }
459 
460 #ifndef QUEST
461 void
462 prl1(int x, int y)
463 {
464 	if (u.dx) {
465 		if (u.dy) {
466 			prl(x - (2 * u.dx), y);
467 			prl(x - u.dx, y);
468 			prl(x, y);
469 			prl(x, y - u.dy);
470 			prl(x, y - (2 * u.dy));
471 		} else {
472 			prl(x, y - 1);
473 			prl(x, y);
474 			prl(x, y + 1);
475 		}
476 	} else {
477 		prl(x - 1, y);
478 		prl(x, y);
479 		prl(x + 1, y);
480 	}
481 }
482 
483 void
484 nose1(int x, int y)
485 {
486 	if (u.dx) {
487 		if (u.dy) {
488 			nosee(x, u.uy);
489 			nosee(x, u.uy - u.dy);
490 			nosee(x, y);
491 			nosee(u.ux - u.dx, y);
492 			nosee(u.ux, y);
493 		} else {
494 			nosee(x, y - 1);
495 			nosee(x, y);
496 			nosee(x, y + 1);
497 		}
498 	} else {
499 		nosee(x - 1, y);
500 		nosee(x, y);
501 		nosee(x + 1, y);
502 	}
503 }
504 #endif /* QUEST */
505 
506 bool
507 vism_at(int x, int y)
508 {
509 	struct monst *mtmp;
510 
511 	return ((x == u.ux && y == u.uy && !Invisible)
512 		? 1 :
513 		(mtmp = m_at(x, y))
514 		? ((Blind && Telepat) || canseemon(mtmp)) :
515 		0);
516 }
517 
518 #ifdef NEWSCR
519 static void
520 pobj(struct obj *obj)
521 {
522 	int show = (!obj->oinvis || See_invisible) &&
523 	    cansee(obj->ox, obj->oy);
524 
525 	if (obj->odispl) {
526 		if (obj->odx != obj->ox || obj->ody != obj->oy || !show)
527 			if (!vism_at(obj->odx, obj->ody)) {
528 				newsym(obj->odx, obj->ody);
529 				obj->odispl = 0;
530 			}
531 	}
532 	if (show && !vism_at(obj->ox, obj->oy)) {
533 		atl(obj->ox, obj->oy, obj->olet);
534 		obj->odispl = 1;
535 		obj->odx = obj->ox;
536 		obj->ody = obj->oy;
537 	}
538 }
539 #endif /* NEWSCR */
540 
541 void
542 unpobj(struct obj *obj)
543 {
544 	if (!vism_at(obj->ox, obj->oy))
545 		newsym(obj->ox, obj->oy);
546 }
547 
548 void
549 seeobjs(void)
550 {
551 	struct obj *obj, *obj2;
552 
553 	for (obj = fobj; obj; obj = obj2) {
554 		obj2 = obj->nobj;
555 		if (obj->olet == FOOD_SYM && obj->otyp >= CORPSE
556 		    && obj->age + 250 < moves)
557 			delobj(obj);
558 	}
559 	for (obj = invent; obj; obj = obj2) {
560 		obj2 = obj->nobj;
561 		if (obj->olet == FOOD_SYM && obj->otyp >= CORPSE
562 		    && obj->age + 250 < moves)
563 			useup(obj);
564 	}
565 }
566 
567 void
568 seemons(void)
569 {
570 	struct monst *mtmp;
571 
572 	for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
573 		if (mtmp->data->mlet == ';')
574 			mtmp->minvis = (u.ustuck != mtmp &&
575 			    levl[mtmp->mx][mtmp->my].typ == POOL);
576 		pmon(mtmp);
577 #ifndef NOWORM
578 		if (mtmp->wormno)
579 			wormsee(mtmp->wormno);
580 #endif /* NOWORM */
581 	}
582 }
583 
584 void
585 pmon(struct monst *mon)
586 {
587 	int show = (Blind && Telepat) || canseemon(mon);
588 
589 	if (mon->mdispl) {
590 		if (mon->mdx != mon->mx || mon->mdy != mon->my || !show)
591 			unpmon(mon);
592 	}
593 	if (show && !mon->mdispl) {
594 		atl(mon->mx, mon->my,
595 		    (!mon->mappearance
596 		    || u.uprops[PROP(RIN_PROTECTION_FROM_SHAPE_CHANGERS)].p_flgs
597 		    ) ? mon->data->mlet : mon->mappearance);
598 		mon->mdispl = 1;
599 		mon->mdx = mon->mx;
600 		mon->mdy = mon->my;
601 	}
602 }
603 
604 void
605 unpmon(struct monst *mon)
606 {
607 	if (mon->mdispl) {
608 		newsym(mon->mdx, mon->mdy);
609 		mon->mdispl = 0;
610 	}
611 }
612 
613 void
614 nscr(void)
615 {
616 	int x, y;
617 	struct rm *room;
618 
619 	if (u.uswallow || u.ux == FAR || flags.nscrinh)
620 		return;
621 	pru();
622 	for (y = scrly; y <= scrhy; y++)
623 		for (x = scrlx; x <= scrhx; x++)
624 			if ((room = &levl[x][y])->new) {
625 				room->new = 0;
626 				at(x, y, room->scrsym);
627 			}
628 	scrhx = scrhy = 0;
629 	scrlx = COLNO;
630 	scrly = ROWNO;
631 }
632 
633 /* 100 suffices for bot(); no relation with COLNO */
634 char oldbot[100], newbot[100];
635 
636 static void
637 cornbot(int lth)
638 {
639 	if (lth < (int)sizeof(oldbot)) {
640 		oldbot[lth] = 0;
641 		flags.botl = 1;
642 	}
643 }
644 
645 void
646 bot(void)
647 {
648 	char *ob = oldbot, *nb = newbot;
649 	int i;
650 
651 	if (flags.botlx)
652 		*ob = 0;
653 	flags.botl = flags.botlx = 0;
654 #ifdef GOLD_ON_BOTL
655 	sprintf(newbot,
656 		"Level %-2d  Gold %-5lu  Hp %3d(%d)  Ac %-2d  Str ",
657 		dlevel, u.ugold, u.uhp, u.uhpmax, u.uac);
658 #else
659 	sprintf(newbot,
660 		"Level %-2d   Hp %3d(%d)   Ac %-2d   Str ",
661 		dlevel, u.uhp, u.uhpmax, u.uac);
662 #endif /* GOLD_ON_BOTL */
663 	if (u.ustr > 18) {
664 		if (u.ustr > 117)
665 			strcat(newbot, "18/**");
666 		else
667 			sprintf(eos(newbot), "18/%02d", u.ustr - 18);
668 	} else
669 		sprintf(eos(newbot), "%-2d   ", u.ustr);
670 #ifdef EXP_ON_BOTL
671 	sprintf(eos(newbot), "  Exp %2d/%-5lu ", u.ulevel, u.uexp);
672 #else
673 	sprintf(eos(newbot), "   Exp %2u  ", u.ulevel);
674 #endif /* EXP_ON_BOTL */
675 	strcat(newbot, hu_stat[u.uhs]);
676 	if (flags.time)
677 		sprintf(eos(newbot), "  %ld", moves);
678 	if (strlen(newbot) >= COLNO) {
679 		char *bp0, *bp1;
680 		bp0 = bp1 = newbot;
681 		do {
682 			if (*bp0 != ' ' || bp0[1] != ' ' || bp0[2] != ' ')
683 				*bp1++ = *bp0;
684 		} while (*bp0++);
685 	}
686 	for (i = 1; i < COLNO; i++) {
687 		if (*ob != *nb) {
688 			curs(i, ROWNO + 2);
689 			putchar(*nb ? *nb : ' ');
690 			curx++;
691 		}
692 		if (*ob)
693 			ob++;
694 		if (*nb)
695 			nb++;
696 	}
697 	strcpy(oldbot, newbot);
698 }
699 
700 #ifdef WAN_PROBING
701 void
702 mstatusline(struct monst *mtmp)
703 {
704 	pline("Status of %s: ", monnam(mtmp));
705 	pline("Level %-2d  Gold %-5lu  Hp %3d(%d)  Ac %-2d  Dam %d",
706 	    mtmp->data->mlevel, mtmp->mgold, mtmp->mhp, mtmp->mhpmax,
707 	    mtmp->data->ac, (mtmp->data->damn + 1) * (mtmp->data->damd + 1));
708 }
709 #endif /* WAN_PROBING */
710 
711 void
712 cls(void)
713 {
714 	if (flags.toplin == 1)
715 		more();
716 	flags.toplin = 0;
717 
718 	clear_screen();
719 
720 	flags.botlx = 1;
721 }
722