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