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