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