1 /* display.c Larn is copyrighted 1986 by Noah Morgan. */ 2 /* $FreeBSD: src/games/larn/display.c,v 1.4 1999/11/16 02:57:21 billf Exp $ */ 3 /* $DragonFly: src/games/larn/display.c,v 1.3 2006/08/26 17:05:05 pavalos Exp $ */ 4 #include "header.h" 5 #define makecode(_a,_b,_c) (((_a)<<16) + ((_b)<<8) + (_c)) 6 7 static int minx,maxx,miny,maxy,k,m; 8 static char bot1f=0,bot2f=0,bot3f=0; 9 char always=0; 10 11 static void bot_hpx(void); 12 static void bot_spellx(void); 13 static void botside(void); 14 static void botsub(int, const char *); 15 static void seepage(void); 16 17 /* 18 bottomline() 19 20 now for the bottom line of the display 21 */ 22 void 23 bottomline(void) 24 { recalc(); bot1f=1; } 25 void 26 bottomhp(void) 27 { bot2f=1; } 28 void 29 bottomspell(void) 30 { bot3f=1; } 31 void 32 bottomdo(void) 33 { 34 if (bot1f) { bot3f=bot1f=bot2f=0; bot_linex(); return; } 35 if (bot2f) { bot2f=0; bot_hpx(); } 36 if (bot3f) { bot3f=0; bot_spellx(); } 37 } 38 39 void 40 bot_linex(void) 41 { 42 int i; 43 if (cbak[SPELLS] <= -50 || (always)) 44 { 45 cursor( 1,18); 46 if (c[SPELLMAX]>99) lprintf("Spells:%3d(%3d)",(long)c[SPELLS],(long)c[SPELLMAX]); 47 else lprintf("Spells:%3d(%2d) ",(long)c[SPELLS],(long)c[SPELLMAX]); 48 lprintf(" AC: %-3d WC: %-3d Level",(long)c[AC],(long)c[WCLASS]); 49 if (c[LEVEL]>99) lprintf("%3d",(long)c[LEVEL]); 50 else lprintf(" %-2d",(long)c[LEVEL]); 51 lprintf(" Exp: %-9d %s\n",(long)c[EXPERIENCE],class[c[LEVEL]-1]); 52 lprintf("HP: %3d(%3d) STR=%-2d INT=%-2d ", 53 (long)c[HP],(long)c[HPMAX],(long)(c[STRENGTH]+c[STREXTRA]),(long)c[INTELLIGENCE]); 54 lprintf("WIS=%-2d CON=%-2d DEX=%-2d CHA=%-2d LV:", 55 (long)c[WISDOM],(long)c[CONSTITUTION],(long)c[DEXTERITY],(long)c[CHARISMA]); 56 57 if ((level==0) || (wizard)) c[TELEFLAG]=0; 58 if (c[TELEFLAG]) lprcat(" ?"); else lprcat(levelname[(int)level]); 59 lprintf(" Gold: %-6d",(long)c[GOLD]); 60 always=1; botside(); 61 c[TMP] = c[STRENGTH]+c[STREXTRA]; 62 for (i=0; i<100; i++) cbak[i]=c[i]; 63 return; 64 } 65 66 botsub(makecode(SPELLS,8,18),"%3d"); 67 if (c[SPELLMAX]>99) botsub(makecode(SPELLMAX,12,18),"%3d)"); 68 else botsub(makecode(SPELLMAX,12,18),"%2d) "); 69 botsub(makecode(HP,5,19),"%3d"); 70 botsub(makecode(HPMAX,9,19),"%3d"); 71 botsub(makecode(AC,21,18),"%-3d"); 72 botsub(makecode(WCLASS,30,18),"%-3d"); 73 botsub(makecode(EXPERIENCE,49,18),"%-9d"); 74 if (c[LEVEL] != cbak[LEVEL]) 75 { cursor(59,18); lprcat(class[c[LEVEL]-1]); } 76 if (c[LEVEL]>99) botsub(makecode(LEVEL,40,18),"%3d"); 77 else botsub(makecode(LEVEL,40,18)," %-2d"); 78 c[TMP] = c[STRENGTH]+c[STREXTRA]; botsub(makecode(TMP,18,19),"%-2d"); 79 botsub(makecode(INTELLIGENCE,25,19),"%-2d"); 80 botsub(makecode(WISDOM,32,19),"%-2d"); 81 botsub(makecode(CONSTITUTION,39,19),"%-2d"); 82 botsub(makecode(DEXTERITY,46,19),"%-2d"); 83 botsub(makecode(CHARISMA,53,19),"%-2d"); 84 if ((level != cbak[CAVELEVEL]) || (c[TELEFLAG] != cbak[TELEFLAG])) 85 { 86 if ((level==0) || (wizard)) c[TELEFLAG]=0; 87 cbak[TELEFLAG] = c[TELEFLAG]; 88 cbak[CAVELEVEL] = level; cursor(59,19); 89 if (c[TELEFLAG]) lprcat(" ?"); else lprcat(levelname[(int)level]); 90 } 91 botsub(makecode(GOLD,69,19),"%-6d"); 92 botside(); 93 } 94 95 /* 96 special subroutine to update only the gold number on the bottomlines 97 called from ogold() 98 */ 99 void 100 bottomgold(void) 101 { 102 botsub(makecode(GOLD,69,19),"%-6d"); 103 } 104 105 /* 106 special routine to update hp and level fields on bottom lines 107 called in monster.c hitplayer() and spattack() 108 */ 109 static void 110 bot_hpx(void) 111 { 112 if (c[EXPERIENCE] != cbak[EXPERIENCE]) 113 { 114 recalc(); bot_linex(); 115 } 116 else botsub(makecode(HP,5,19),"%3d"); 117 } 118 119 /* 120 special routine to update number of spells called from regen() 121 */ 122 static void 123 bot_spellx(void) 124 { 125 botsub(makecode(SPELLS,9,18),"%2d"); 126 } 127 128 /* 129 common subroutine for a more economical bottomline() 130 */ 131 static struct bot_side_def 132 { 133 int typ; 134 const char *string; 135 } 136 bot_data[] = 137 { 138 { STEALTH, "stealth" }, { UNDEADPRO, "undead pro" }, { SPIRITPRO, "spirit pro" }, 139 { CHARMCOUNT, "Charm" }, { TIMESTOP, "Time Stop" }, { HOLDMONST, "Hold Monst" }, 140 { GIANTSTR, "Giant Str" }, { FIRERESISTANCE, "Fire Resit" }, { DEXCOUNT, "Dexterity" }, 141 { STRCOUNT, "Strength" }, { SCAREMONST, "Scare" }, { HASTESELF, "Haste Self" }, 142 { CANCELLATION, "Cancel" }, { INVISIBILITY, "Invisible" }, { ALTPRO, "Protect 3" }, 143 { PROTECTIONTIME, "Protect 2" }, { WTW, "Wall-Walk"} 144 }; 145 146 static void 147 botside(void) 148 { 149 int i,idx; 150 for (i=0; i<17; i++) 151 { 152 idx = bot_data[i].typ; 153 if ((always) || (c[idx] != cbak[idx])) 154 { 155 if ((always) || (cbak[idx] == 0)) 156 { if (c[idx]) { cursor(70,i+1); lprcat(bot_data[i].string); } } else 157 if (c[idx]==0) { cursor(70,i+1); lprcat(" "); } 158 cbak[idx]=c[idx]; 159 } 160 } 161 always=0; 162 } 163 164 static void 165 botsub(int idx, const char *str) 166 { 167 int x,y; 168 y = idx & 0xff; x = (idx>>8) & 0xff; idx >>= 16; 169 if (c[idx] != cbak[idx]) 170 { cbak[idx]=c[idx]; cursor(x,y); lprintf(str,(long)c[idx]); } 171 } 172 173 /* 174 * subroutine to draw only a section of the screen 175 * only the top section of the screen is updated. If entire lines are being 176 * drawn, then they will be cleared first. 177 */ 178 int d_xmin=0,d_xmax=MAXX,d_ymin=0,d_ymax=MAXY; /* for limited screen drawing */ 179 180 void 181 draws(int xmin, int xmax, int ymin, int ymax) 182 { 183 int i,idx; 184 if (xmin==0 && xmax==MAXX) /* clear section of screen as needed */ 185 { 186 if (ymin==0) cl_up(79,ymax); 187 else for (i=ymin; i<ymin; i++) cl_line(1,i+1); 188 xmin = -1; 189 } 190 d_xmin=xmin; d_xmax=xmax; d_ymin=ymin; d_ymax=ymax; /* for limited screen drawing */ 191 drawscreen(); 192 if (xmin<=0 && xmax==MAXX) /* draw stuff on right side of screen as needed*/ 193 { 194 for (i=ymin; i<ymax; i++) 195 { 196 idx = bot_data[i].typ; 197 if (c[idx]) 198 { 199 cursor(70,i+1); lprcat(bot_data[i].string); 200 } 201 cbak[idx]=c[idx]; 202 } 203 } 204 } 205 206 /* 207 drawscreen() 208 209 subroutine to redraw the whole screen as the player knows it 210 */ 211 char screen[MAXX][MAXY],d_flag; /* template for the screen */ 212 213 void 214 drawscreen(void) 215 { 216 int i,j,l; 217 int lastx,lasty; /* variables used to optimize the object printing */ 218 if (d_xmin==0 && d_xmax==MAXX && d_ymin==0 && d_ymax==MAXY) 219 { 220 d_flag=1; clear(); /* clear the screen */ 221 } 222 else 223 { 224 d_flag=0; cursor(1,1); 225 } 226 if (d_xmin<0) 227 d_xmin=0; /* d_xmin=-1 means display all without bottomline */ 228 229 for (i=d_ymin; i<d_ymax; i++) 230 for (j=d_xmin; j<d_xmax; j++) 231 if (know[j][i]==0) screen[j][i] = ' '; else 232 if ((l=mitem[j][i])) screen[j][i] = monstnamelist[l]; else 233 if ((l=item[j][i])==OWALL) screen[j][i] = '#'; 234 else screen[j][i] = ' '; 235 236 for (i=d_ymin; i<d_ymax; i++) 237 { 238 j=d_xmin; while ((screen[j][i]==' ') && (j<d_xmax)) j++; 239 /* was m=0 */ 240 if (j >= d_xmax) m=d_xmin; /* don't search backwards if blank line */ 241 else 242 { /* search backwards for end of line */ 243 m=d_xmax-1; while ((screen[m][i]==' ') && (m>d_xmin)) --m; 244 if (j<=m) cursor(j+1,i+1); else continue; 245 } 246 while (j <= m) 247 { 248 if (j <= m-3) 249 { 250 for (l=j; l<=j+3; l++) if (screen[l][i] != ' ') l=1000; 251 if (l < 1000) 252 { while(screen[j][i]==' ' && j<=m) j++; cursor(j+1,i+1); } 253 } 254 lprc(screen[j++][i]); 255 } 256 } 257 setbold(); /* print out only bold objects now */ 258 259 for (lastx=lasty=127, i=d_ymin; i<d_ymax; i++) 260 for (j=d_xmin; j<d_xmax; j++) 261 { 262 if ((l=item[j][i])) 263 if (l != OWALL) 264 if ((know[j][i]) && (mitem[j][i]==0)) 265 if (objnamelist[l]!=' ') 266 { 267 if (lasty!=i+1 || lastx!=j) 268 cursor(lastx=j+1,lasty=i+1); else lastx++; 269 lprc(objnamelist[l]); 270 } 271 } 272 273 resetbold(); if (d_flag) { always=1; botside(); always=1; bot_linex(); } 274 oldx=99; 275 d_xmin = 0 , d_xmax = MAXX , d_ymin = 0 , d_ymax = MAXY; /* for limited screen drawing */ 276 } 277 278 /* 279 showcell(x,y) 280 281 subroutine to display a cell location on the screen 282 */ 283 void 284 showcell(int x, int y) 285 { 286 int i,j,l,n; 287 if (c[BLINDCOUNT]) return; /* see nothing if blind */ 288 if (c[AWARENESS]) { minx = x-3; maxx = x+3; miny = y-3; maxy = y+3; } 289 else { minx = x-1; maxx = x+1; miny = y-1; maxy = y+1; } 290 291 if (minx < 0) minx=0; if (maxx > MAXX-1) maxx = MAXX-1; 292 if (miny < 0) miny=0; if (maxy > MAXY-1) maxy = MAXY-1; 293 294 for (j=miny; j<=maxy; j++) 295 for (n=minx; n<=maxx; n++) 296 if (know[n][j]==0) 297 { 298 cursor(n+1,j+1); 299 x=maxx; while (know[x][j]) --x; 300 for (i=n; i<=x; i++) 301 { 302 if ((l=mitem[i][j]) != 0) lprc(monstnamelist[l]); 303 else switch(l=item[i][j]) 304 { 305 case OWALL: case 0: case OIVTELETRAP: case OTRAPARROWIV: 306 case OIVDARTRAP: case OIVTRAPDOOR: 307 lprc(objnamelist[l]); break; 308 309 default: setbold(); lprc(objnamelist[l]); resetbold(); 310 }; 311 know[i][j]=1; 312 } 313 n = maxx; 314 } 315 } 316 317 /* 318 this routine shows only the spot that is given it. the spaces around 319 these coordinated are not shown 320 used in godirect() in monster.c for missile weapons display 321 */ 322 void 323 show1cell(int x, int y) 324 { 325 if (c[BLINDCOUNT]) return; /* see nothing if blind */ 326 cursor(x+1,y+1); 327 if ((k=mitem[x][y]) != 0) lprc(monstnamelist[k]); 328 else switch(k=item[x][y]) 329 { 330 case OWALL: case 0: case OIVTELETRAP: case OTRAPARROWIV: 331 case OIVDARTRAP: case OIVTRAPDOOR: 332 lprc(objnamelist[k]); break; 333 334 default: setbold(); lprc(objnamelist[k]); resetbold(); 335 }; 336 know[x][y]|=1; /* we end up knowing about it */ 337 } 338 339 /* 340 showplayer() 341 342 subroutine to show where the player is on the screen 343 cursor values start from 1 up 344 */ 345 void 346 showplayer(void) 347 { 348 cursor(playerx+1,playery+1); 349 oldx=playerx; oldy=playery; 350 } 351 352 /* 353 moveplayer(dir) 354 355 subroutine to move the player from one room to another 356 returns 0 if can't move in that direction or hit a monster or on an object 357 else returns 1 358 nomove is set to 1 to stop the next move (inadvertent monsters hitting 359 players when walking into walls) if player walks off screen or into wall 360 */ 361 short diroffx[] = { 0, 0, 1, 0, -1, 1, -1, 1, -1 }; 362 short diroffy[] = { 0, 1, 0, -1, 0, -1, -1, 1, 1 }; 363 364 int 365 moveplayer(int dir) 366 /* from = present room # direction = [1-north] 367 [2-east] [3-south] [4-west] [5-northeast] 368 [6-northwest] [7-southeast] [8-southwest] 369 if direction=0, don't move--just show where he is */ 370 { 371 int l,n,i,j; 372 if (c[CONFUSE]) if (c[LEVEL]<rnd(30)) dir=rund(9); /*if confused any dir*/ 373 l = playerx + diroffx[dir]; n = playery + diroffy[dir]; 374 if (l<0 || l>=MAXX || n<0 || n>=MAXY) { nomove=1; return(yrepcount = 0); } 375 i = item[l][n]; j = mitem[l][n]; 376 if (i==OWALL && c[WTW]==0) { nomove=1; return(yrepcount = 0); } /* hit a wall */ 377 if (l==33 && n==MAXY-1 && level==1) 378 { 379 newcavelevel(0); for (l=0; l<MAXX; l++) for (n=0; n<MAXY; n++) 380 if (item[l][n]==OENTRANCE) 381 { playerx=l; playery=n; positionplayer(); drawscreen(); return(0); } 382 } 383 if (j>0) { hitmonster(l,n); return(yrepcount = 0); } /* hit a monster*/ 384 lastpx = playerx; lastpy = playery; 385 playerx = l; playery = n; 386 if (i && i!=OTRAPARROWIV && i!=OIVTELETRAP && i!=OIVDARTRAP && i!=OIVTRAPDOOR) return(yrepcount = 0); else return(1); 387 } 388 389 /* 390 * function to show what magic items have been discovered thus far 391 * enter with -1 for just spells, anything else will give scrolls & potions 392 */ 393 static int lincount,count; 394 395 void 396 seemagic(int arg) 397 { 398 int i,number = 0; 399 count = lincount = 0; nosignal=1; 400 401 if (arg== -1) /* if display spells while casting one */ 402 { 403 for (number=i=0; i<SPNUM; i++) if (spelknow[i]) number++; 404 number = (number+2)/3 + 4; /* # lines needed to display */ 405 cl_up(79,number); cursor(1,1); 406 } 407 else 408 { 409 resetscroll(); clear(); 410 } 411 412 lprcat("The magic spells you have discovered thus far:\n\n"); 413 for (i=0; i<SPNUM; i++) 414 if (spelknow[i]) 415 { lprintf("%s %-20s ",spelcode[i],spelname[i]); seepage(); } 416 417 if (arg== -1) 418 { 419 seepage(); more(); nosignal=0; 420 draws(0,MAXX,0,number); return; 421 } 422 423 lincount += 3; if (count!=0) { count=2; seepage(); } 424 425 lprcat("\nThe magic scrolls you have found to date are:\n\n"); 426 count=0; 427 for (i=0; i<MAXSCROLL; i++) 428 if (scrollname[i][0]) 429 if (scrollname[i][1]!=' ') 430 { lprintf("%-26s",&scrollname[i][1]); seepage(); } 431 432 lincount += 3; if (count!=0) { count=2; seepage(); } 433 434 lprcat("\nThe magic potions you have found to date are:\n\n"); 435 count=0; 436 for (i=0; i<MAXPOTION; i++) 437 if (potionname[i][0]) 438 if (potionname[i][1]!=' ') 439 { lprintf("%-26s",&potionname[i][1]); seepage(); } 440 441 if (lincount!=0) more(); nosignal=0; setscroll(); drawscreen(); 442 } 443 444 /* 445 * subroutine to paginate the seemagic function 446 */ 447 static void 448 seepage(void) 449 { 450 if (++count==3) 451 { 452 lincount++; count=0; lprc('\n'); 453 if (lincount>17) { lincount=0; more(); clear(); } 454 } 455 } 456