1 /* $NetBSD: execute.c,v 1.9 2009/07/04 04:29:54 dholland Exp $ */ 2 /* 3 * Copyright (c) 1983-2003, Regents of the University of California. 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions are 8 * met: 9 * 10 * + Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * + Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * + Neither the name of the University of California, San Francisco nor 16 * the names of its contributors may be used to endorse or promote 17 * products derived from this software without specific prior written 18 * permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 21 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 23 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 #include <sys/cdefs.h> 34 #ifndef lint 35 __RCSID("$NetBSD: execute.c,v 1.9 2009/07/04 04:29:54 dholland Exp $"); 36 #endif /* not lint */ 37 38 #include <stdlib.h> 39 #include "hunt.h" 40 41 static void cloak(PLAYER *); 42 static void turn_player(PLAYER *, int); 43 static void fire(PLAYER *, int); 44 static void fire_slime(PLAYER *, int); 45 static void move_player(PLAYER *, int); 46 static void pickup(PLAYER *, int, int, int, int); 47 static void scan(PLAYER *); 48 49 50 #ifdef MONITOR 51 /* 52 * mon_execute: 53 * Execute a single monitor command 54 */ 55 void 56 mon_execute(PLAYER *pp) 57 { 58 char ch; 59 60 ch = pp->p_cbuf[pp->p_ncount++]; 61 switch (ch) { 62 case CTRL('L'): 63 sendcom(pp, REDRAW); 64 break; 65 case 'q': 66 (void) strcpy(pp->p_death, "| Quit |"); 67 break; 68 } 69 } 70 #endif 71 72 /* 73 * execute: 74 * Execute a single command 75 */ 76 void 77 execute(PLAYER *pp) 78 { 79 char ch; 80 81 ch = pp->p_cbuf[pp->p_ncount++]; 82 83 #ifdef FLY 84 if (pp->p_flying >= 0) { 85 switch (ch) { 86 case CTRL('L'): 87 sendcom(pp, REDRAW); 88 break; 89 case 'q': 90 (void) strcpy(pp->p_death, "| Quit |"); 91 break; 92 } 93 return; 94 } 95 #endif 96 97 switch (ch) { 98 case CTRL('L'): 99 sendcom(pp, REDRAW); 100 break; 101 case 'h': 102 move_player(pp, LEFTS); 103 break; 104 case 'H': 105 turn_player(pp, LEFTS); 106 break; 107 case 'j': 108 move_player(pp, BELOW); 109 break; 110 case 'J': 111 turn_player(pp, BELOW); 112 break; 113 case 'k': 114 move_player(pp, ABOVE); 115 break; 116 case 'K': 117 turn_player(pp, ABOVE); 118 break; 119 case 'l': 120 move_player(pp, RIGHT); 121 break; 122 case 'L': 123 turn_player(pp, RIGHT); 124 break; 125 case 'f': 126 case '1': 127 fire(pp, 0); /* SHOT */ 128 break; 129 case 'g': 130 case '2': 131 fire(pp, 1); /* GRENADE */ 132 break; 133 case 'F': 134 case '3': 135 fire(pp, 2); /* SATCHEL */ 136 break; 137 case 'G': 138 case '4': 139 fire(pp, 3); /* 7x7 BOMB */ 140 break; 141 case '5': 142 fire(pp, 4); /* 9x9 BOMB */ 143 break; 144 case '6': 145 fire(pp, 5); /* 11x11 BOMB */ 146 break; 147 case '7': 148 fire(pp, 6); /* 13x13 BOMB */ 149 break; 150 case '8': 151 fire(pp, 7); /* 15x15 BOMB */ 152 break; 153 case '9': 154 fire(pp, 8); /* 17x17 BOMB */ 155 break; 156 case '0': 157 fire(pp, 9); /* 19x19 BOMB */ 158 break; 159 case '@': 160 fire(pp, 10); /* 21x21 BOMB */ 161 break; 162 #ifdef OOZE 163 case 'o': 164 fire_slime(pp, 0); /* SLIME */ 165 break; 166 case 'O': 167 fire_slime(pp, 1); /* SSLIME */ 168 break; 169 case 'p': 170 fire_slime(pp, 2); 171 break; 172 case 'P': 173 fire_slime(pp, 3); 174 break; 175 #endif 176 case 's': 177 scan(pp); 178 break; 179 case 'c': 180 cloak(pp); 181 break; 182 case 'q': 183 (void) strcpy(pp->p_death, "| Quit |"); 184 break; 185 } 186 } 187 188 /* 189 * move_player: 190 * Execute a move in the given direction 191 */ 192 static void 193 move_player(PLAYER *pp, int dir) 194 { 195 PLAYER *newp; 196 int x, y; 197 FLAG moved; 198 BULLET *bp; 199 200 y = pp->p_y; 201 x = pp->p_x; 202 203 switch (dir) { 204 case LEFTS: 205 x--; 206 break; 207 case RIGHT: 208 x++; 209 break; 210 case ABOVE: 211 y--; 212 break; 213 case BELOW: 214 y++; 215 break; 216 } 217 218 moved = FALSE; 219 switch (Maze[y][x]) { 220 case SPACE: 221 #ifdef RANDOM 222 case DOOR: 223 #endif 224 moved = TRUE; 225 break; 226 case WALL1: 227 case WALL2: 228 case WALL3: 229 #ifdef REFLECT 230 case WALL4: 231 case WALL5: 232 #endif 233 break; 234 case MINE: 235 case GMINE: 236 if (dir == pp->p_face) 237 pickup(pp, y, x, 2, Maze[y][x]); 238 else if (opposite(dir, pp->p_face)) 239 pickup(pp, y, x, 95, Maze[y][x]); 240 else 241 pickup(pp, y, x, 50, Maze[y][x]); 242 Maze[y][x] = SPACE; 243 moved = TRUE; 244 break; 245 case SHOT: 246 case GRENADE: 247 case SATCHEL: 248 case BOMB: 249 #ifdef OOZE 250 case SLIME: 251 #endif 252 #ifdef DRONE 253 case DSHOT: 254 #endif 255 bp = is_bullet(y, x); 256 if (bp != NULL) 257 bp->b_expl = TRUE; 258 Maze[y][x] = SPACE; 259 moved = TRUE; 260 break; 261 case LEFTS: 262 case RIGHT: 263 case ABOVE: 264 case BELOW: 265 if (dir != pp->p_face) 266 sendcom(pp, BELL); 267 else { 268 newp = play_at(y, x); 269 checkdam(newp, pp, pp->p_ident, STABDAM, KNIFE); 270 } 271 break; 272 #ifdef FLY 273 case FLYER: 274 newp = play_at(y, x); 275 message(newp, "Oooh, there's a short guy waving at you!"); 276 message(pp, "You couldn't quite reach him!"); 277 break; 278 #endif 279 #ifdef BOOTS 280 case BOOT: 281 case BOOT_PAIR: 282 if (Maze[y][x] == BOOT) 283 pp->p_nboots++; 284 else 285 pp->p_nboots += 2; 286 for (newp = Boot; newp < &Boot[NBOOTS]; newp++) { 287 if (newp->p_flying < 0) 288 continue; 289 if (newp->p_y == y && newp->p_x == x) { 290 newp->p_flying = -1; 291 if (newp->p_undershot) 292 fixshots(y, x, newp->p_over); 293 } 294 } 295 if (pp->p_nboots == 2) 296 message(pp, "Wow! A pair of boots!"); 297 else 298 message(pp, "You can hobble around on one boot."); 299 Maze[y][x] = SPACE; 300 moved = TRUE; 301 break; 302 #endif 303 } 304 if (moved) { 305 if (pp->p_ncshot > 0) 306 if (--pp->p_ncshot == MAXNCSHOT) { 307 cgoto(pp, STAT_GUN_ROW, STAT_VALUE_COL); 308 outstr(pp, " ok", 3); 309 } 310 if (pp->p_undershot) { 311 fixshots(pp->p_y, pp->p_x, pp->p_over); 312 pp->p_undershot = FALSE; 313 } 314 drawplayer(pp, FALSE); 315 pp->p_over = Maze[y][x]; 316 pp->p_y = y; 317 pp->p_x = x; 318 drawplayer(pp, TRUE); 319 } 320 } 321 322 /* 323 * turn_player: 324 * Change the direction the player is facing 325 */ 326 static void 327 turn_player(PLAYER *pp, int dir) 328 { 329 if (pp->p_face != dir) { 330 pp->p_face = dir; 331 drawplayer(pp, TRUE); 332 } 333 } 334 335 /* 336 * fire: 337 * Fire a shot of the given type in the given direction 338 */ 339 static void 340 fire(PLAYER *pp, int req_index) 341 { 342 if (pp == NULL) 343 return; 344 #ifdef DEBUG 345 if (req_index < 0 || req_index >= MAXBOMB) 346 message(pp, "What you do?"); 347 #endif 348 while (req_index >= 0 && pp->p_ammo < shot_req[req_index]) 349 req_index--; 350 if (req_index < 0) { 351 message(pp, "Not enough charges."); 352 return; 353 } 354 if (pp->p_ncshot > MAXNCSHOT) 355 return; 356 if (pp->p_ncshot++ == MAXNCSHOT) { 357 cgoto(pp, STAT_GUN_ROW, STAT_VALUE_COL); 358 outstr(pp, " ", 3); 359 } 360 pp->p_ammo -= shot_req[req_index]; 361 (void) snprintf(Buf, sizeof(Buf), "%3d", pp->p_ammo); 362 cgoto(pp, STAT_AMMO_ROW, STAT_VALUE_COL); 363 outstr(pp, Buf, 3); 364 365 add_shot(shot_type[req_index], pp->p_y, pp->p_x, pp->p_face, 366 shot_req[req_index], pp, FALSE, pp->p_face); 367 pp->p_undershot = TRUE; 368 369 /* 370 * Show the object to everyone 371 */ 372 showexpl(pp->p_y, pp->p_x, shot_type[req_index]); 373 for (pp = Player; pp < End_player; pp++) 374 sendcom(pp, REFRESH); 375 #ifdef MONITOR 376 for (pp = Monitor; pp < End_monitor; pp++) 377 sendcom(pp, REFRESH); 378 #endif 379 } 380 381 #ifdef OOZE 382 /* 383 * fire_slime: 384 * Fire a slime shot in the given direction 385 */ 386 static void 387 fire_slime(PLAYER *pp, int req_index) 388 { 389 if (pp == NULL) 390 return; 391 #ifdef DEBUG 392 if (req_index < 0 || req_index >= MAXSLIME) 393 message(pp, "What you do?"); 394 #endif 395 while (req_index >= 0 && pp->p_ammo < slime_req[req_index]) 396 req_index--; 397 if (req_index < 0) { 398 message(pp, "Not enough charges."); 399 return; 400 } 401 if (pp->p_ncshot > MAXNCSHOT) 402 return; 403 if (pp->p_ncshot++ == MAXNCSHOT) { 404 cgoto(pp, STAT_GUN_ROW, STAT_VALUE_COL); 405 outstr(pp, " ", 3); 406 } 407 pp->p_ammo -= slime_req[req_index]; 408 (void) snprintf(Buf, sizeof(Buf), "%3d", pp->p_ammo); 409 cgoto(pp, STAT_AMMO_ROW, STAT_VALUE_COL); 410 outstr(pp, Buf, 3); 411 412 add_shot(SLIME, pp->p_y, pp->p_x, pp->p_face, 413 slime_req[req_index] * SLIME_FACTOR, pp, FALSE, pp->p_face); 414 pp->p_undershot = TRUE; 415 416 /* 417 * Show the object to everyone 418 */ 419 showexpl(pp->p_y, pp->p_x, SLIME); 420 for (pp = Player; pp < End_player; pp++) 421 sendcom(pp, REFRESH); 422 #ifdef MONITOR 423 for (pp = Monitor; pp < End_monitor; pp++) 424 sendcom(pp, REFRESH); 425 #endif 426 } 427 #endif 428 429 /* 430 * add_shot: 431 * Create a shot with the given properties 432 */ 433 void 434 add_shot(int type, int y, int x, char face, int charge, 435 PLAYER *owner, int expl, char over) 436 { 437 BULLET *bp; 438 int size; 439 440 switch (type) { 441 case SHOT: 442 case MINE: 443 size = 1; 444 break; 445 case GRENADE: 446 case GMINE: 447 size = 2; 448 break; 449 case SATCHEL: 450 size = 3; 451 break; 452 case BOMB: 453 for (size = 3; size < MAXBOMB; size++) 454 if (shot_req[size] >= charge) 455 break; 456 size++; 457 break; 458 default: 459 size = 0; 460 break; 461 } 462 463 bp = create_shot(type, y, x, face, charge, size, owner, 464 (owner == NULL) ? NULL : owner->p_ident, expl, over); 465 bp->b_next = Bullets; 466 Bullets = bp; 467 } 468 469 BULLET * 470 create_shot(int type, int y, int x, char face, int charge, 471 int size, PLAYER *owner, IDENT *score, int expl, char over) 472 { 473 BULLET *bp; 474 475 bp = malloc(sizeof(*bp)); 476 if (bp == NULL) { 477 if (owner != NULL) 478 message(owner, "Out of memory"); 479 return NULL; 480 } 481 482 bp->b_face = face; 483 bp->b_x = x; 484 bp->b_y = y; 485 bp->b_charge = charge; 486 bp->b_owner = owner; 487 bp->b_score = score; 488 bp->b_type = type; 489 bp->b_size = size; 490 bp->b_expl = expl; 491 bp->b_over = over; 492 bp->b_next = NULL; 493 494 return bp; 495 } 496 497 /* 498 * cloak: 499 * Turn on or increase length of a cloak 500 */ 501 static void 502 cloak(PLAYER *pp) 503 { 504 if (pp->p_ammo <= 0) { 505 message(pp, "No more charges"); 506 return; 507 } 508 #ifdef BOOTS 509 if (pp->p_nboots > 0) { 510 message(pp, "Boots are too noisy to cloak!"); 511 return; 512 } 513 #endif 514 (void) snprintf(Buf, sizeof(Buf), "%3d", --pp->p_ammo); 515 cgoto(pp, STAT_AMMO_ROW, STAT_VALUE_COL); 516 outstr(pp, Buf, 3); 517 518 pp->p_cloak += CLOAKLEN; 519 520 if (pp->p_scan >= 0) 521 pp->p_scan = -1; 522 523 showstat(pp); 524 } 525 526 /* 527 * scan: 528 * Turn on or increase length of a scan 529 */ 530 static void 531 scan(PLAYER *pp) 532 { 533 if (pp->p_ammo <= 0) { 534 message(pp, "No more charges"); 535 return; 536 } 537 (void) snprintf(Buf, sizeof(Buf), "%3d", --pp->p_ammo); 538 cgoto(pp, STAT_AMMO_ROW, STAT_VALUE_COL); 539 outstr(pp, Buf, 3); 540 541 pp->p_scan += SCANLEN; 542 543 if (pp->p_cloak >= 0) 544 pp->p_cloak = -1; 545 546 showstat(pp); 547 } 548 549 /* 550 * pickup: 551 * check whether the object blew up or whether he picked it up 552 */ 553 void 554 pickup(PLAYER *pp, int y, int x, int prob, int obj) 555 { 556 int req; 557 558 switch (obj) { 559 case MINE: 560 req = BULREQ; 561 break; 562 case GMINE: 563 req = GRENREQ; 564 break; 565 default: 566 abort(); 567 } 568 if (rand_num(100) < prob) 569 add_shot(obj, y, x, LEFTS, req, (PLAYER *) NULL, 570 TRUE, pp->p_face); 571 else { 572 pp->p_ammo += req; 573 (void) snprintf(Buf, sizeof(Buf), "%3d", pp->p_ammo); 574 cgoto(pp, STAT_AMMO_ROW, STAT_VALUE_COL); 575 outstr(pp, Buf, 3); 576 } 577 } 578