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