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