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