1 /* $NetBSD: execute.c,v 1.5 2008/01/28 03:23:29 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.5 2008/01/28 03:23:29 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(pp) 57 PLAYER *pp; 58 { 59 char ch; 60 61 ch = pp->p_cbuf[pp->p_ncount++]; 62 switch (ch) { 63 case CTRL('L'): 64 sendcom(pp, REDRAW); 65 break; 66 case 'q': 67 (void) strcpy(pp->p_death, "| Quit |"); 68 break; 69 } 70 } 71 # endif 72 73 /* 74 * execute: 75 * Execute a single command 76 */ 77 void 78 execute(pp) 79 PLAYER *pp; 80 { 81 char ch; 82 83 ch = pp->p_cbuf[pp->p_ncount++]; 84 85 # ifdef FLY 86 if (pp->p_flying >= 0) { 87 switch (ch) { 88 case CTRL('L'): 89 sendcom(pp, REDRAW); 90 break; 91 case 'q': 92 (void) strcpy(pp->p_death, "| Quit |"); 93 break; 94 } 95 return; 96 } 97 # endif 98 99 switch (ch) { 100 case CTRL('L'): 101 sendcom(pp, REDRAW); 102 break; 103 case 'h': 104 move_player(pp, LEFTS); 105 break; 106 case 'H': 107 turn_player(pp, LEFTS); 108 break; 109 case 'j': 110 move_player(pp, BELOW); 111 break; 112 case 'J': 113 turn_player(pp, BELOW); 114 break; 115 case 'k': 116 move_player(pp, ABOVE); 117 break; 118 case 'K': 119 turn_player(pp, ABOVE); 120 break; 121 case 'l': 122 move_player(pp, RIGHT); 123 break; 124 case 'L': 125 turn_player(pp, RIGHT); 126 break; 127 case 'f': 128 case '1': 129 fire(pp, 0); /* SHOT */ 130 break; 131 case 'g': 132 case '2': 133 fire(pp, 1); /* GRENADE */ 134 break; 135 case 'F': 136 case '3': 137 fire(pp, 2); /* SATCHEL */ 138 break; 139 case 'G': 140 case '4': 141 fire(pp, 3); /* 7x7 BOMB */ 142 break; 143 case '5': 144 fire(pp, 4); /* 9x9 BOMB */ 145 break; 146 case '6': 147 fire(pp, 5); /* 11x11 BOMB */ 148 break; 149 case '7': 150 fire(pp, 6); /* 13x13 BOMB */ 151 break; 152 case '8': 153 fire(pp, 7); /* 15x15 BOMB */ 154 break; 155 case '9': 156 fire(pp, 8); /* 17x17 BOMB */ 157 break; 158 case '0': 159 fire(pp, 9); /* 19x19 BOMB */ 160 break; 161 case '@': 162 fire(pp, 10); /* 21x21 BOMB */ 163 break; 164 # ifdef OOZE 165 case 'o': 166 fire_slime(pp, 0); /* SLIME */ 167 break; 168 case 'O': 169 fire_slime(pp, 1); /* SSLIME */ 170 break; 171 case 'p': 172 fire_slime(pp, 2); 173 break; 174 case 'P': 175 fire_slime(pp, 3); 176 break; 177 # endif 178 case 's': 179 scan(pp); 180 break; 181 case 'c': 182 cloak(pp); 183 break; 184 case 'q': 185 (void) strcpy(pp->p_death, "| Quit |"); 186 break; 187 } 188 } 189 190 /* 191 * move_player: 192 * Execute a move in the given direction 193 */ 194 static void 195 move_player(pp, dir) 196 PLAYER *pp; 197 int dir; 198 { 199 PLAYER *newp; 200 int x, y; 201 FLAG moved; 202 BULLET *bp; 203 204 y = pp->p_y; 205 x = pp->p_x; 206 207 switch (dir) { 208 case LEFTS: 209 x--; 210 break; 211 case RIGHT: 212 x++; 213 break; 214 case ABOVE: 215 y--; 216 break; 217 case BELOW: 218 y++; 219 break; 220 } 221 222 moved = FALSE; 223 switch (Maze[y][x]) { 224 case SPACE: 225 # ifdef RANDOM 226 case DOOR: 227 # endif 228 moved = TRUE; 229 break; 230 case WALL1: 231 case WALL2: 232 case WALL3: 233 # ifdef REFLECT 234 case WALL4: 235 case WALL5: 236 # endif 237 break; 238 case MINE: 239 case GMINE: 240 if (dir == pp->p_face) 241 pickup(pp, y, x, 2, Maze[y][x]); 242 else if (opposite(dir, pp->p_face)) 243 pickup(pp, y, x, 95, Maze[y][x]); 244 else 245 pickup(pp, y, x, 50, Maze[y][x]); 246 Maze[y][x] = SPACE; 247 moved = TRUE; 248 break; 249 case SHOT: 250 case GRENADE: 251 case SATCHEL: 252 case BOMB: 253 # ifdef OOZE 254 case SLIME: 255 # endif 256 # ifdef DRONE 257 case DSHOT: 258 # endif 259 bp = is_bullet(y, x); 260 if (bp != NULL) 261 bp->b_expl = TRUE; 262 Maze[y][x] = SPACE; 263 moved = TRUE; 264 break; 265 case LEFTS: 266 case RIGHT: 267 case ABOVE: 268 case BELOW: 269 if (dir != pp->p_face) 270 sendcom(pp, BELL); 271 else { 272 newp = play_at(y, x); 273 checkdam(newp, pp, pp->p_ident, STABDAM, KNIFE); 274 } 275 break; 276 # ifdef FLY 277 case FLYER: 278 newp = play_at(y, x); 279 message(newp, "Oooh, there's a short guy waving at you!"); 280 message(pp, "You couldn't quite reach him!"); 281 break; 282 # endif 283 # ifdef BOOTS 284 case BOOT: 285 case BOOT_PAIR: 286 if (Maze[y][x] == BOOT) 287 pp->p_nboots++; 288 else 289 pp->p_nboots += 2; 290 for (newp = Boot; newp < &Boot[NBOOTS]; newp++) { 291 if (newp->p_flying < 0) 292 continue; 293 if (newp->p_y == y && newp->p_x == x) { 294 newp->p_flying = -1; 295 if (newp->p_undershot) 296 fixshots(y, x, newp->p_over); 297 } 298 } 299 if (pp->p_nboots == 2) 300 message(pp, "Wow! A pair of boots!"); 301 else 302 message(pp, "You can hobble around on one boot."); 303 Maze[y][x] = SPACE; 304 moved = TRUE; 305 break; 306 # endif 307 } 308 if (moved) { 309 if (pp->p_ncshot > 0) 310 if (--pp->p_ncshot == MAXNCSHOT) { 311 cgoto(pp, STAT_GUN_ROW, STAT_VALUE_COL); 312 outstr(pp, " ok", 3); 313 } 314 if (pp->p_undershot) { 315 fixshots(pp->p_y, pp->p_x, pp->p_over); 316 pp->p_undershot = FALSE; 317 } 318 drawplayer(pp, FALSE); 319 pp->p_over = Maze[y][x]; 320 pp->p_y = y; 321 pp->p_x = x; 322 drawplayer(pp, TRUE); 323 } 324 } 325 326 /* 327 * turn_player: 328 * Change the direction the player is facing 329 */ 330 static void 331 turn_player(pp, dir) 332 PLAYER *pp; 333 int dir; 334 { 335 if (pp->p_face != dir) { 336 pp->p_face = dir; 337 drawplayer(pp, TRUE); 338 } 339 } 340 341 /* 342 * fire: 343 * Fire a shot of the given type in the given direction 344 */ 345 static void 346 fire(pp, req_index) 347 PLAYER *pp; 348 int req_index; 349 { 350 if (pp == NULL) 351 return; 352 # ifdef DEBUG 353 if (req_index < 0 || req_index >= MAXBOMB) 354 message(pp, "What you do?"); 355 # endif 356 while (req_index >= 0 && pp->p_ammo < shot_req[req_index]) 357 req_index--; 358 if (req_index < 0) { 359 message(pp, "Not enough charges."); 360 return; 361 } 362 if (pp->p_ncshot > MAXNCSHOT) 363 return; 364 if (pp->p_ncshot++ == MAXNCSHOT) { 365 cgoto(pp, STAT_GUN_ROW, STAT_VALUE_COL); 366 outstr(pp, " ", 3); 367 } 368 pp->p_ammo -= shot_req[req_index]; 369 (void) sprintf(Buf, "%3d", pp->p_ammo); 370 cgoto(pp, STAT_AMMO_ROW, STAT_VALUE_COL); 371 outstr(pp, Buf, 3); 372 373 add_shot(shot_type[req_index], pp->p_y, pp->p_x, pp->p_face, 374 shot_req[req_index], pp, FALSE, pp->p_face); 375 pp->p_undershot = TRUE; 376 377 /* 378 * Show the object to everyone 379 */ 380 showexpl(pp->p_y, pp->p_x, shot_type[req_index]); 381 for (pp = Player; pp < End_player; pp++) 382 sendcom(pp, REFRESH); 383 # ifdef MONITOR 384 for (pp = Monitor; pp < End_monitor; pp++) 385 sendcom(pp, REFRESH); 386 # endif 387 } 388 389 # ifdef OOZE 390 /* 391 * fire_slime: 392 * Fire a slime shot in the given direction 393 */ 394 static void 395 fire_slime(pp, req_index) 396 PLAYER *pp; 397 int req_index; 398 { 399 if (pp == NULL) 400 return; 401 # ifdef DEBUG 402 if (req_index < 0 || req_index >= MAXSLIME) 403 message(pp, "What you do?"); 404 # endif 405 while (req_index >= 0 && pp->p_ammo < slime_req[req_index]) 406 req_index--; 407 if (req_index < 0) { 408 message(pp, "Not enough charges."); 409 return; 410 } 411 if (pp->p_ncshot > MAXNCSHOT) 412 return; 413 if (pp->p_ncshot++ == MAXNCSHOT) { 414 cgoto(pp, STAT_GUN_ROW, STAT_VALUE_COL); 415 outstr(pp, " ", 3); 416 } 417 pp->p_ammo -= slime_req[req_index]; 418 (void) sprintf(Buf, "%3d", pp->p_ammo); 419 cgoto(pp, STAT_AMMO_ROW, STAT_VALUE_COL); 420 outstr(pp, Buf, 3); 421 422 add_shot(SLIME, pp->p_y, pp->p_x, pp->p_face, 423 slime_req[req_index] * SLIME_FACTOR, pp, FALSE, pp->p_face); 424 pp->p_undershot = TRUE; 425 426 /* 427 * Show the object to everyone 428 */ 429 showexpl(pp->p_y, pp->p_x, SLIME); 430 for (pp = Player; pp < End_player; pp++) 431 sendcom(pp, REFRESH); 432 # ifdef MONITOR 433 for (pp = Monitor; pp < End_monitor; pp++) 434 sendcom(pp, REFRESH); 435 # endif 436 } 437 # endif 438 439 /* 440 * add_shot: 441 * Create a shot with the given properties 442 */ 443 void 444 add_shot(type, y, x, face, charge, owner, expl, over) 445 int type; 446 int y, x; 447 char face; 448 int charge; 449 PLAYER *owner; 450 int expl; 451 char over; 452 { 453 BULLET *bp; 454 int size; 455 456 switch (type) { 457 case SHOT: 458 case MINE: 459 size = 1; 460 break; 461 case GRENADE: 462 case GMINE: 463 size = 2; 464 break; 465 case SATCHEL: 466 size = 3; 467 break; 468 case BOMB: 469 for (size = 3; size < MAXBOMB; size++) 470 if (shot_req[size] >= charge) 471 break; 472 size++; 473 break; 474 default: 475 size = 0; 476 break; 477 } 478 479 bp = create_shot(type, y, x, face, charge, size, owner, 480 (owner == NULL) ? NULL : owner->p_ident, expl, over); 481 bp->b_next = Bullets; 482 Bullets = bp; 483 } 484 485 BULLET * 486 create_shot(type, y, x, face, charge, size, owner, score, expl, over) 487 int type; 488 int y, x; 489 char face; 490 int charge; 491 int size; 492 PLAYER *owner; 493 IDENT *score; 494 int expl; 495 char over; 496 { 497 BULLET *bp; 498 499 bp = (BULLET *) malloc(sizeof (BULLET)); /* NOSTRICT */ 500 if (bp == NULL) { 501 if (owner != NULL) 502 message(owner, "Out of memory"); 503 return NULL; 504 } 505 506 bp->b_face = face; 507 bp->b_x = x; 508 bp->b_y = y; 509 bp->b_charge = charge; 510 bp->b_owner = owner; 511 bp->b_score = score; 512 bp->b_type = type; 513 bp->b_size = size; 514 bp->b_expl = expl; 515 bp->b_over = over; 516 bp->b_next = NULL; 517 518 return bp; 519 } 520 521 /* 522 * cloak: 523 * Turn on or increase length of a cloak 524 */ 525 static void 526 cloak(pp) 527 PLAYER *pp; 528 { 529 if (pp->p_ammo <= 0) { 530 message(pp, "No more charges"); 531 return; 532 } 533 # ifdef BOOTS 534 if (pp->p_nboots > 0) { 535 message(pp, "Boots are too noisy to cloak!"); 536 return; 537 } 538 # endif 539 (void) sprintf(Buf, "%3d", --pp->p_ammo); 540 cgoto(pp, STAT_AMMO_ROW, STAT_VALUE_COL); 541 outstr(pp, Buf, 3); 542 543 pp->p_cloak += CLOAKLEN; 544 545 if (pp->p_scan >= 0) 546 pp->p_scan = -1; 547 548 showstat(pp); 549 } 550 551 /* 552 * scan: 553 * Turn on or increase length of a scan 554 */ 555 static void 556 scan(pp) 557 PLAYER *pp; 558 { 559 if (pp->p_ammo <= 0) { 560 message(pp, "No more charges"); 561 return; 562 } 563 (void) sprintf(Buf, "%3d", --pp->p_ammo); 564 cgoto(pp, STAT_AMMO_ROW, STAT_VALUE_COL); 565 outstr(pp, Buf, 3); 566 567 pp->p_scan += SCANLEN; 568 569 if (pp->p_cloak >= 0) 570 pp->p_cloak = -1; 571 572 showstat(pp); 573 } 574 575 /* 576 * pickup: 577 * check whether the object blew up or whether he picked it up 578 */ 579 void 580 pickup(pp, y, x, prob, obj) 581 PLAYER *pp; 582 int y, x; 583 int prob; 584 int obj; 585 { 586 int req; 587 588 switch (obj) { 589 case MINE: 590 req = BULREQ; 591 break; 592 case GMINE: 593 req = GRENREQ; 594 break; 595 default: 596 abort(); 597 } 598 if (rand_num(100) < prob) 599 add_shot(obj, y, x, LEFTS, req, (PLAYER *) NULL, 600 TRUE, pp->p_face); 601 else { 602 pp->p_ammo += req; 603 (void) sprintf(Buf, "%3d", pp->p_ammo); 604 cgoto(pp, STAT_AMMO_ROW, STAT_VALUE_COL); 605 outstr(pp, Buf, 3); 606 } 607 } 608