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