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