xref: /openbsd/games/hunt/huntd/draw.c (revision c72b5b24)
1 /*	$OpenBSD: draw.c,v 1.6 2002/02/16 21:27:10 millert Exp $	*/
2 /*	$NetBSD: draw.c,v 1.2 1997/10/10 16:33:04 lukem Exp $	*/
3 /*
4  *  Hunt
5  *  Copyright (c) 1985 Conrad C. Huang, Gregory S. Couch, Kenneth C.R.C. Arnold
6  *  San Francisco, California
7  */
8 
9 #include <string.h>
10 
11 #include "hunt.h"
12 #include "server.h"
13 #include "conf.h"
14 
15 static char	translate(char);
16 static int	player_sym(PLAYER *, int, int);
17 static void	drawstatus(PLAYER *);
18 static void	see(PLAYER *, int);
19 
20 /*
21  * drawmaze:
22  *	Draw the entire maze on a player's screen.
23  */
24 void
25 drawmaze(pp)
26 	PLAYER	*pp;
27 {
28 	int	x;
29 	char	*sp;
30 	int	y;
31 	char	*endp;
32 
33 	/* Clear the client's screen: */
34 	clrscr(pp);
35 	/* Draw the top row of the maze: */
36 	outstr(pp, pp->p_maze[0], WIDTH);
37 	for (y = 1; y < HEIGHT - 1; y++) {
38 		endp = &pp->p_maze[y][WIDTH];
39 		for (x = 0, sp = pp->p_maze[y]; sp < endp; x++, sp++)
40 			if (*sp != SPACE) {
41 				cgoto(pp, y, x);
42 				/* Draw the player as themselves */
43 				if (pp->p_x == x && pp->p_y == y)
44 					outch(pp, translate(*sp));
45 				/* Possibly draw other players as team nrs */
46 				else if (is_player(*sp))
47 					outch(pp, player_sym(pp, y, x));
48 				else
49 					outch(pp, *sp);
50 			}
51 	}
52 	/* Draw the last row of the maze: */
53 	cgoto(pp, HEIGHT - 1, 0);
54 	outstr(pp, pp->p_maze[HEIGHT - 1], WIDTH);
55 	drawstatus(pp);
56 }
57 
58 /*
59  * drawstatus - put up the status lines (this assumes the screen
60  *		size is 80x24 with the maze being 64x24)
61  */
62 static void
63 drawstatus(pp)
64 	PLAYER	*pp;
65 {
66 	int	i;
67 	PLAYER	*np;
68 
69 	outyx(pp, STAT_AMMO_ROW, STAT_LABEL_COL, "Ammo:");
70 	ammo_update(pp);
71 
72 	outyx(pp, STAT_GUN_ROW,  STAT_LABEL_COL, "Gun:");
73 	outyx(pp, STAT_GUN_ROW,  STAT_VALUE_COL, "%3s",
74 		(pp->p_ncshot < conf_maxncshot) ? "ok" : "");
75 
76 	outyx(pp, STAT_DAM_ROW,  STAT_LABEL_COL, "Damage:");
77 	outyx(pp, STAT_DAM_ROW,  STAT_VALUE_COL, "%2d/%2d",
78 		pp->p_damage, pp->p_damcap);
79 
80 	outyx(pp, STAT_KILL_ROW, STAT_LABEL_COL, "Kills:");
81 	outyx(pp, STAT_KILL_ROW, STAT_VALUE_COL, "%3d",
82 		(pp->p_damcap - conf_maxdam) / 2);
83 
84 	outyx(pp, STAT_PLAY_ROW, STAT_LABEL_COL, "Player:");
85 	for (i = STAT_PLAY_ROW + 1, np = Player; np < End_player; np++, i++) {
86 		outyx(pp, i, STAT_NAME_COL, "%5.2f%c%-10.10s %c",
87 			np->p_ident->i_score, stat_char(np),
88 			np->p_ident->i_name, np->p_ident->i_team);
89 	}
90 
91 	outyx(pp, STAT_MON_ROW, STAT_LABEL_COL, "Monitor:");
92 	for (i = STAT_MON_ROW + 1, np = Monitor; np < End_monitor; np++, i++) {
93 		outyx(pp, i++, STAT_NAME_COL, "%5.5s %-10.10s %c",
94 			" ", np->p_ident->i_name, np->p_ident->i_team);
95 	}
96 }
97 
98 /*
99  * look
100  *	check and update the visible area around the player
101  */
102 void
103 look(pp)
104 	PLAYER	*pp;
105 {
106 	int	x, y;
107 
108 	x = pp->p_x;
109 	y = pp->p_y;
110 
111 	/*
112 	 * The player is aware of all objects immediately adjacent to
113 	 * their position:
114 	 */
115 	check(pp, y - 1, x - 1);
116 	check(pp, y - 1, x    );
117 	check(pp, y - 1, x + 1);
118 	check(pp, y    , x - 1);
119 	check(pp, y    , x    );
120 	check(pp, y    , x + 1);
121 	check(pp, y + 1, x - 1);
122 	check(pp, y + 1, x    );
123 	check(pp, y + 1, x + 1);
124 
125 	switch (pp->p_face) {
126 	  /* The player can see down corridors in directions except behind: */
127 	  case LEFTS:
128 		see(pp, LEFTS);
129 		see(pp, ABOVE);
130 		see(pp, BELOW);
131 		break;
132 	  case RIGHT:
133 		see(pp, RIGHT);
134 		see(pp, ABOVE);
135 		see(pp, BELOW);
136 		break;
137 	  case ABOVE:
138 		see(pp, ABOVE);
139 		see(pp, LEFTS);
140 		see(pp, RIGHT);
141 		break;
142 	  case BELOW:
143 		see(pp, BELOW);
144 		see(pp, LEFTS);
145 		see(pp, RIGHT);
146 		break;
147 	  /* But they don't see too far when they are flying about: */
148 	  case FLYER:
149 		break;
150 	}
151 
152 	/* Move the cursor back over the player: */
153 	cgoto(pp, y, x);
154 }
155 
156 /*
157  * see
158  *	Look down a corridor, or towards an open space. This
159  *	is a simulation of visibility from the player's perspective.
160  */
161 static void
162 see(pp, face)
163 	PLAYER	*pp;
164 	int	face;
165 {
166 	char	*sp;
167 	int	y, x;
168 
169 	/* Start from the player's position: */
170 	x = pp->p_x;
171 	y = pp->p_y;
172 
173 	#define seewalk(dx, dy) 					\
174 		x += (dx);						\
175 		y += (dy);						\
176 		sp = &Maze[y][x];					\
177 		while (See_over[(int)*sp]) {				\
178 			x += (dx);					\
179 			y += (dy);					\
180 			sp += ((dx) + (dy) * sizeof Maze[0]);		\
181 			check(pp, y + dx, x + dy);			\
182 			check(pp, y, x);				\
183 			check(pp, y - dx, x - dy);			\
184 		}
185 
186 	switch (face) {
187 	  case LEFTS:
188 		seewalk(-1, 0); break;
189 	  case RIGHT:
190 		seewalk(1, 0); break;
191 	  case ABOVE:
192 		seewalk(0, -1); break;
193 	  case BELOW:
194 		seewalk(0, 1); break;
195 	}
196 }
197 
198 /*
199  * check
200  *	The player is aware of a cell in the maze.
201  *	Ensure it is shown properly on their screen.
202  */
203 void
204 check(pp, y, x)
205 	PLAYER	*pp;
206 	int	y, x;
207 {
208 	int	index;
209 	int	ch;
210 	PLAYER	*rpp;
211 
212 	if (pp == ALL_PLAYERS) {
213 		for (pp = Player; pp < End_player; pp++)
214 			check(pp, y, x);
215 		for (pp = Monitor; pp < End_monitor; pp++)
216 			check(pp, y, x);
217 		return;
218 	}
219 
220 	index = y * sizeof Maze[0] + x;
221 	ch = ((char *) Maze)[index];
222 	if (ch != ((char *) pp->p_maze)[index]) {
223 		rpp = pp;
224 		cgoto(rpp, y, x);
225 		if (x == rpp->p_x && y == rpp->p_y)
226 			outch(rpp, translate(ch));
227 		else if (is_player(ch))
228 			outch(rpp, player_sym(rpp, y, x));
229 		else
230 			outch(rpp, ch);
231 		((char *) rpp->p_maze)[index] = ch;
232 	}
233 }
234 
235 /*
236  * showstat
237  *	Update the status of a player on everyone's screen
238  */
239 void
240 showstat(pp)
241 	PLAYER	*pp;
242 {
243 
244 	outyx(ALL_PLAYERS,
245 		STAT_PLAY_ROW + 1 + (pp - Player), STAT_SCAN_COL,
246 		"%c", stat_char(pp));
247 }
248 
249 /*
250  * drawplayer:
251  *	Draw the player on the screen and show him to everyone who's scanning
252  *	unless he is cloaked.
253  *	The 'draw' flag when false, causes the 'saved under' character to
254  *	be drawn instead of the player; effectively un-drawing the player.
255  */
256 void
257 drawplayer(pp, draw)
258 	PLAYER	*pp;
259 	FLAG	draw;
260 {
261 	PLAYER	*newp;
262 	int	x, y;
263 
264 	x = pp->p_x;
265 	y = pp->p_y;
266 
267 	/* Draw or un-draw the player into the master map: */
268 	Maze[y][x] = draw ? pp->p_face : pp->p_over;
269 
270 	/* The monitors can always see this player: */
271 	for (newp = Monitor; newp < End_monitor; newp++)
272 		check(newp, y, x);
273 
274 	/* Check if other players can see this player: */
275 	for (newp = Player; newp < End_player; newp++) {
276 		if (!draw) {
277 			/* When un-drawing, show everyone what was under */
278 			check(newp, y, x);
279 			continue;
280 		}
281 		if (newp == pp) {
282 			/* The player can always see themselves: */
283 			check(newp, y, x);
284 			continue;
285 		}
286 		/* Check if the other player just run out of scans */
287 		if (newp->p_scan == 0) {
288 			/* The other player is no longer scanning: */
289 			newp->p_scan--;
290 			showstat(newp);
291 		/* Check if the other play is scannning */
292 		} else if (newp->p_scan > 0) {
293 			/* If this player's not cloacked, draw him: */
294 			if (pp->p_cloak < 0)
295 				check(newp, y, x);
296 			/* And this uses up a scan. */
297 			newp->p_scan--;
298 		}
299 	}
300 
301 	/* Use up one point of cloak time when drawing: */
302 	if (draw && pp->p_cloak >= 0) {
303 		pp->p_cloak--;
304 		/* Check if we ran out of cloak: */
305 		if (pp->p_cloak < 0)
306 			showstat(pp);
307 	}
308 }
309 
310 /*
311  * message:
312  *	Write a message at the bottom of the screen.
313  */
314 void
315 message(pp, s)
316 	PLAYER	*pp;
317 	char	*s;
318 {
319 	cgoto(pp, HEIGHT, 0);
320 	outstr(pp, s, strlen(s));
321 	ce(pp);
322 }
323 
324 /*
325  * translate:
326  *	Turn a player character into a more personal player character.
327  *	ie: {,},!,i becomes <,>,v,^
328  */
329 static char
330 translate(ch)
331 	char	ch;
332 {
333 	switch (ch) {
334 	  case LEFTS:
335 		return '<';
336 	  case RIGHT:
337 		return '>';
338 	  case ABOVE:
339 		return '^';
340 	  case BELOW:
341 		return 'v';
342 	}
343 	return ch;
344 }
345 
346 /*
347  * player_sym:
348  *	Return the symbol for the player at (y,x) when viewed by player 'pp'.
349  *	ie: - unteamed players appear as {,},!,i
350  *	    - unteamed monitors see all players as team digits
351  *	    - teamed players see other players on their team, as a digit
352  */
353 static int
354 player_sym(pp, y, x)
355 	PLAYER	*pp;
356 	int	y, x;
357 {
358 	PLAYER	*npp;
359 
360 	npp = play_at(y, x);
361 	if (npp->p_ident->i_team == ' ')
362 		return Maze[y][x];
363 	if (pp->p_ident->i_team == '*')
364 		return npp->p_ident->i_team;
365 	if (pp->p_ident->i_team != npp->p_ident->i_team)
366 		return Maze[y][x];
367 	return pp->p_ident->i_team;
368 }
369