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