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
drawmaze(PLAYER * pp)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
drawstatus(PLAYER * pp)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
look(PLAYER * pp)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
see(PLAYER * pp,int face)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
check(PLAYER * pp,int y,int x)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
showstat(PLAYER * pp)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
drawplayer(PLAYER * pp,FLAG draw)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
message(PLAYER * pp,const char * s)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
translate(char ch)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
player_sym(PLAYER * pp,int y,int x)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