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