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