xref: /dragonfly/games/larn/display.c (revision f746689a)
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