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