Merge branch 'vendor/BZIP'
[games.git] / games / hack / hack.pri.c
... / ...
CommitLineData
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>
8xchar scrlx, scrhx, scrly, scrhy; /* corners of new area on screen */
9
10extern char *CD;
11
12#ifdef NEWSCR
13static void pobj(struct obj *);
14#endif
15static void cornbot(int);
16
17void
18swallowed(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 */
40boolean panicking;
41
42void
43panic(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
65void
66atl(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
81void
82on_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
101void
102tmp_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 */
133void
134Tmp_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
174void
175setclipped(void)
176{
177 error("Hack needs a screen of size at least %d by %d.\n",
178 ROWNO + 2, COLNO);
179}
180
181void
182at(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
201void
202prme(void)
203{
204 if (!Invisible)
205 at(u.ux, u.uy, u.usym);
206}
207
208int
209doredraw(void)
210{
211 docrt();
212 return (0);
213}
214
215void
216docrt(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
256void
257docorner(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
297void
298curs_on_u(void)
299{
300 curs(u.ux, u.uy + 2);
301}
302
303void
304pru(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
322extern struct wseg *m_atseg;
323#endif /* NOWORM */
324
325/* print a position that is visible for @ */
326void
327prl(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
367char
368news0(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
421void
422newsym(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 */
429void
430mnewsym(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
445void
446nosee(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
461void
462prl1(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
483void
484nose1(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
506bool
507vism_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
519static void
520pobj(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
541void
542unpobj(struct obj *obj)
543{
544 if (!vism_at(obj->ox, obj->oy))
545 newsym(obj->ox, obj->oy);
546}
547
548void
549seeobjs(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
567void
568seemons(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
584void
585pmon(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
604void
605unpmon(struct monst *mon)
606{
607 if (mon->mdispl) {
608 newsym(mon->mdx, mon->mdy);
609 mon->mdispl = 0;
610 }
611}
612
613void
614nscr(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 */
634char oldbot[100], newbot[100];
635
636static void
637cornbot(int lth)
638{
639 if (lth < (int)sizeof(oldbot)) {
640 oldbot[lth] = 0;
641 flags.botl = 1;
642 }
643}
644
645void
646bot(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
701void
702mstatusline(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
711void
712cls(void)
713{
714 if (flags.toplin == 1)
715 more();
716 flags.toplin = 0;
717
718 clear_screen();
719
720 flags.botlx = 1;
721}