1 /* $OpenBSD: draw.c,v 1.10 2016/08/27 02:06:40 guenther 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 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 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 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 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 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 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 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 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 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 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