xref: /dragonfly/games/hunt/huntd/draw.c (revision 86d7f5d305c6adaa56ff4582ece9859d73106103)
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